In his 1987 paper (Cognitive Social Structures), Krackhardt includes data from a 21-member network of managers (all male) at a tech manufacturing company. These data include not only egocentric reports (these are the people I go to for advice), but also allocentric reports (I think John often asks Bill for advice). We can try testing whether multistep relational abstraction explains the subjects’ allocentric beliefs in this dataset.

Setup

# Set a random seed for reproducibility
set.seed(sum(utf8ToInt("krackhardt")))

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.2     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.3     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(here)
## here() starts at /Users/jaeyoungson/Documents/GitHub/multistep-relational-abstraction
library(tidygraph)
## 
## Attaching package: 'tidygraph'
## 
## The following object is masked from 'package:stats':
## 
##     filter
library(ggraph)
library(patchwork)
library(lme4)
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## 
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
library(lmerTest)
## 
## Attaching package: 'lmerTest'
## 
## The following object is masked from 'package:lme4':
## 
##     lmer
## 
## The following object is masked from 'package:stats':
## 
##     step
library(broom.mixed)

kable <- knitr::kable
vif <- car::vif

knitting <- knitr::is_html_output()

if (knitting) {
  # Create directories for saving stuff
  if (!dir.exists(here("outputs"))) {
    dir.create(here("outputs"))
  }
  
  if (!dir.exists(here("outputs", "07-krackhardt"))) {
    dir.create(here("outputs", "07-krackhardt"))
  }
}

# Pull in some modeling tools
source(here("code", "utils", "representation_utils.R"))
source(here("code", "utils", "network_utils.R"))

gg <- list(
  theme_bw(),
  theme(
    plot.title = element_text(hjust = 0.5, size = 13),
    plot.subtitle = element_text(hjust = 0.5, size = 11),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.spacing = unit(0.75, "lines"),
    legend.box.spacing = unit(0.5, "lines"),
    legend.margin = margin(c(0, 0, 0, 0), unit = "lines")
  )
)

plot_representation <- function(rep_df, relation_value, n_breaks = 3) {
  plot_df <- rep_df %>%
    filter(from != to) %>%
    group_by(from, to) %>%
    summarise(value = mean({{relation_value}}), .groups = "drop")
  
  plot_df %>%
    # Plot
    mutate(
      across(c(from, to), factor),
      from = fct_rev(from)
    ) %>%
    ggplot(aes(x=to, y=from, fill=value)) +
    gg +
    geom_tile() +
    coord_fixed() +
    scale_fill_viridis_c(
      option = "magma", name = NULL, na.value = "white", n.breaks = n_breaks
    ) +
    theme(
      legend.position = "bottom",
      axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)
    )
}

check_significance <- function(tidy_stats) {
  tidy_stats %>%
    mutate(
      significance = case_when(
        p.value < 0.001 ~ "***",
        p.value < 0.01 ~ "**",
        p.value < 0.05 ~ "*",
        p.value < 0.1 ~ ".",
        TRUE ~ ""
      )
    )
}

These data are included in Krackhardt 1987, Appendix A. Each allocentric CSV contains an adjacency matrix, so we’ll need to do a little work to get them into a tidy-friendly format.

The “egocentric” network is defined in the way that social networks are most often defined: based on each subject’s answer to the question, “Who are you connected to?” Oftentimes, this question is phrased to measure friendships (e.g., “Are you friends with X?”). In this particular dataset, the question is something closer to “Who do you ask for advice?”

The “allocentric” cognitive maps measure each subject’s answer to the question, “Does X ask Y for advice?” This includes the special case of, “Does X ask you for advice?” Here’s the rationale for including the special case in allocentric maps. Imagine for a moment that this were a study about friendships instead of advice-giving. In that case, we would consider “Are you friends with X?” to be a question that subjects would know the answer to (or at least, they would know better than anyone else). On the other hand, we would consider the question “Does X consider you a friend?” to be more of an inference than knowledge. I don’t know whether X considers me a friend; I don’t consider X to be a friend, but we do occasionally eat lunch together. Moreover, in cases of disagreement (X says he asks Y for advice; Y doesn’t agree), the “ground truth” egocentric network would then hinge on the researcher’s decision to use an intersection vs union rule to resolve disagreements; Krackhardt notes this in his paper. By alternatively defining the egocentric network based solely on the responses that subjects would have greatest introspective access to (their own advice-seeking behavior), we sidestep this researcher degree of freedom.

krackhardt_raw <- here("data", "krackhardt") %>%
  fs::dir_ls(regexp = "krackhardt_tech_managers_sub[[:digit:]]{2}\\.csv") %>%
  map_dfr(
    .f = ~read_csv(.x, col_names = FALSE, show_col_types = FALSE),
    .id = "filename"
  ) %>%
  mutate(
    sub_id = str_extract(filename, "sub[[:digit:]]{2}"),
    sub_id = str_remove(sub_id, "sub"),
    sub_id = as.numeric(sub_id)
  ) %>%
  select(-filename) %>%
  group_by(sub_id) %>%
  mutate(from = row_number()) %>%
  ungroup() %>%
  pivot_longer(
    cols = -c(sub_id, from),
    names_to = "to",
    values_to = "edge"
  ) %>%
  mutate(
    to = str_remove(to, "X"),
    to = as.integer(to)
  )

krackhardt_egocentric <- krackhardt_raw %>%
  filter(sub_id == from, from != to) %>%
  select(-sub_id)

krackhardt_allocentric <- krackhardt_raw %>%
  filter(sub_id != from, from != to)

Plot data

Okay, let’s try and get a sense for what the “egocentric” network looks like.

krackhardt_g <- krackhardt_egocentric %>%
  filter(edge == 1) %>%
  select(-edge) %>% 
  tbl_graph(edges = .) %>%
  mutate(name = row_number())

plot_network_graph <- krackhardt_g %>%
  mutate(Degree = centrality_degree(mode = "in")) %>%
  # Plot the "ground truth" network
  ggraph(layout = "stress") +
  geom_edge_link(
    aes(
      start_cap = label_rect(node1.name, padding = margin(15, 15, 15, 15)),
      end_cap = label_rect(node2.name, padding = margin(15, 15, 15, 15)),
    ),
    arrow = arrow(length = unit(5, "pt"), type = "closed")
  ) +
  geom_node_label(
    aes(label = name, size = Degree),
    fill = "grey95", show.legend = FALSE
  ) +
  scale_size(range = c(3, 10)) +
  theme(
    panel.background = element_blank(),
    strip.background = element_blank(),
    panel.border = element_blank(),
    axis.title = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    plot.title = element_text(hjust = 0.5, size = 13),
    strip.text = element_text(hjust = 0.5, size = 13),
    legend.position = "bottom"
  )

plot_network_graph
## Warning: Using the `size` aesthetic in this geom was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` in the `default_aes` field and elsewhere instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

We can also plot this as a matrix instead of a graph, which will ease comparison with the cognitive strategies we’ll consider next.

plot_network_adj <- krackhardt_egocentric %>%
  plot_representation(edge, n_breaks = 2) +
  ggtitle("Egocentric Network")

plot_network_adj

How does this compare to subjects’ mental representation of the network?

plot_choice <- krackhardt_allocentric %>%
  plot_representation(relation_value = edge) +
  ggtitle("Network Representation")

plot_network_adj | plot_choice

In the original paper, Krackhardt makes the following note: “There are some centers of focus for advice, notably 2 and 21 (both are vice presidents) … In [the subjectively perceived network], 21 loses his prominence as a major recipient of nominations: instead, 18, 14, and 7 (the president) appear to be more central.” To get a quantitative sense for this in our data, we can try calculating the “perceived” degree centrality by summing over the matrix columns, then comparing that against the “true” in-degree centrality.

centrality_differences <- krackhardt_g %>%
  mutate(
    Degree = centrality_degree(mode = "in"),
    Betweenness = centrality_betweenness(directed = TRUE)
  ) %>%
  as_tibble() %>%
  # Add represented in-degree; standardize sum by number of network members
  left_join(
    krackhardt_allocentric %>%
      group_by(name = to) %>%
      summarise(Perceived = sum(edge)/21, .groups = "drop"),
    by = c("name")
  ) %>%
  select(name, Perceived, everything()) %>%
  arrange(desc(Degree), desc(Perceived))

We can see that the same number of managers go to subjects 18 and 21 for advice (15 each), but that subject 18 is perceived as being much more “popular” (averaged across subjects, 11.95 managers are perceived to go to him for advice) than subject 21 (averaged across subjects, 8.38 managers are perceived to go to him for advice). A similar phenomenon happens with subjects 1 and 7, where subject 1 is perceived as being much less popular than subject 7, despite their having the same “true” popularity.

centrality_differences %>%
  ggplot(aes(x=Degree, y=Perceived)) +
  gg +
  geom_smooth(method = "lm", se = FALSE) +
  geom_label(aes(label = name)) +
  scale_x_continuous(name = "True (degree) centrality") +
  scale_y_continuous(name = "Perceived centrality")
## `geom_smooth()` using formula = 'y ~ x'

centrality_differences %>%
  select(name, Degree, Perceived) %>%
  kable()
name Degree Perceived
2 18 13.047619
18 15 11.952381
21 15 8.380952
7 13 10.380952
1 13 5.095238
11 11 6.761905
14 10 11.428571
6 10 4.904762
8 10 4.666667
10 9 3.952381
17 9 3.809524
20 8 4.190476
4 8 4.000000
16 8 3.428571
12 7 3.190476
5 5 4.761905
3 5 4.476191
19 4 4.619048
15 4 2.809524
13 4 2.714286
9 4 2.619048

Is it possible that subjects’ network representations might be reflecting some other centrality metric? In the original paper, Krackhardt notes that betweenness seems to have some predictive power. For the 18-21 and 1-7 test cases, we see that betweenness centrality does make the “correct” prediction about which network member is represented as being more important. But, we should note that betweenness doesn’t do the greatest job predicting perceived popularity across the board; its greatest predictive power is in explaining the popularity discrepancy for the most popular managers.

centrality_differences %>%
  pivot_longer(cols = Degree:Betweenness, names_to = "metric") %>%
  ggplot(aes(x=value, y=Perceived)) +
  gg +
  facet_wrap(~metric, scales = "free_x") +
  geom_smooth(method = "lm", se = FALSE) +
  geom_label(aes(label = name)) +
  scale_x_continuous(name = "True centrality") +
  scale_y_continuous(name = "Perceived centrality")
## `geom_smooth()` using formula = 'y ~ x'

centrality_differences %>%
  kable()
name Perceived Degree Betweenness
2 13.047619 18 5.9357143
18 11.952381 15 88.9166667
21 8.380952 15 60.1269841
7 10.380952 13 27.6246032
1 5.095238 13 13.7468254
11 6.761905 11 1.1984127
14 11.428571 10 0.5888889
6 4.904762 10 0.0000000
8 4.666667 10 3.9746032
10 3.952381 9 18.2968254
17 3.809524 9 2.5317460
20 4.190476 8 7.9793651
4 4.000000 8 13.7087302
16 3.428571 8 0.7000000
12 3.190476 7 0.2539683
5 4.761905 5 5.0785714
3 4.476191 5 6.6047619
19 4.619048 4 0.7539683
15 2.809524 4 6.1325397
13 2.714286 4 0.8928571
9 2.619048 4 3.9539683

Simulated observations

We know that an individual’s embedding within a network dictates what interactions and/or relationships they’re able to observe. Therefore, when building predicted cognitive maps, we should use a different set of interactions to inform each subject’s predicted representations. Of course, we have no idea what individual subjects’ observations actually are. So we’ll need to come up with a compact and reasonable set of assumptions about what observations were most likely available to individual network members.

Here are three key assumptions we’ll make here:

  1. We’ll assume (trivially) that people can observe interactions between themselves and their immediate advisors (and/or advisees).
  2. We’ll also assume that people are generally able to observe interactions between advisors-of-advisors (and/or advisees-of-advisees), either through firsthand observation or secondhand chatter.
  3. Though of course it’s plausible that people might observe more distant interactions, we’ll assume this happens with enough infrequency that we can ignore those interactions for the sake of modeling.

We’ve left open an ambiguity in those assumptions: are people observing advisors-of-advisors, and/or advisees-of-advisees? To aid understanding, we’ll use the following example. Suppose we’re looking at a subset of a network consisting of the grad student Abby, who asks the postdoc Betty for advice; in turn, Betty the postdoc asks Cathy the assistant professor for advice; and Cathy asks Dani the associate professor for advice. There are three reasonable ways that observations might work in this network:

  1. Observations go “out”: When Abby asks Betty for advice, Betty responds by sharing the wisdom she’s gained from asking Cathy for advice. That leads Abby to observe that Betty goes to Cathy for advice.
  2. Observations go “in”: Betty has asked Cathy for advice. Cathy thinks Betty has asked a great question that she doesn’t know the answer to, so Cathy asks Dani about it. That leads Dani to observe that Betty goes to Cathy for advice.
  3. It goes both ways.

We may be able to test this empirically. We would need to simulate a set of observations consistent with all three possibilities, generate model predictions from those simulations, then compare how well those models fit managers’ actual perceptions of the network.

# Observations go both ways
obs_edgelist_all <- expand_grid(
  sub_id = 1:21,
  # Start with all one-step egocentric observations
  krackhardt_egocentric
) %>%
  # Convert adjlist into edgelist
  filter(edge == 1) %>%
  select(-edge) %>%
  # For a given node, we want to know who their "advisors-of-advisors" are
  # (or equivalently, "advisees-of-advisees")
  left_join(
    krackhardt_g %>%
      mutate(neighbors = local_members(order = 1, mode = "all")) %>%
      as_tibble(),
    by = c("sub_id" = "name")
  ) %>%
  # We assume that nodes are able to observe (directly or through chatter)
  # advice-giving interactions from their advisors and advisors-of-advisors
  # (or equivalently, advisees and advisees-of-advisees)
  rowwise() %>%
  filter((from %in% neighbors) | (to %in% neighbors)) %>%
  ungroup() %>%
  select(-neighbors) %>%
  # Make pretty
  arrange(sub_id, from)

# Advisees observe who advises their advisors
obs_edgelist_out <- expand_grid(
  sub_id = 1:21,
  krackhardt_egocentric
) %>%
  filter(edge == 1) %>%
  select(-edge) %>%
  left_join(
    krackhardt_g %>%
      mutate(neighbors = local_members(order = 1, mode = "out")) %>%
      as_tibble(),
    by = c("sub_id" = "name")
  ) %>%
  rowwise() %>%
  filter((from %in% neighbors) | (to %in% neighbors)) %>%
  ungroup() %>%
  select(-neighbors) %>%
  arrange(sub_id, from)

# Advisors observe who their advisees advise
obs_edgelist_in <- expand_grid(
  sub_id = 1:21,
  krackhardt_egocentric
) %>%
  filter(edge == 1) %>%
  select(-edge) %>%
  left_join(
    krackhardt_g %>%
      mutate(neighbors = local_members(order = 1, mode = "in")) %>%
      as_tibble(),
    by = c("sub_id" = "name")
  ) %>%
  rowwise() %>%
  filter((from %in% neighbors) | (to %in% neighbors)) %>%
  ungroup() %>%
  select(-neighbors) %>%
  arrange(sub_id, from)

obs_adjlist_all <- expand_grid(sub_id = 1:21, from = sub_id, to = sub_id) %>%
  left_join(
    obs_edgelist_all %>% mutate(edge = 1),
    by = c("sub_id", "from", "to")
  ) %>%
  mutate(edge = if_else(is.na(edge), 0, edge))

obs_adjlist_out <- expand_grid(sub_id = 1:21, from = sub_id, to = sub_id) %>%
  left_join(
    obs_edgelist_out %>% mutate(edge = 1),
    by = c("sub_id", "from", "to")
  ) %>%
  mutate(edge = if_else(is.na(edge), 0, edge))

obs_adjlist_in <- expand_grid(sub_id = 1:21, from = sub_id, to = sub_id) %>%
  left_join(
    obs_edgelist_in %>% mutate(edge = 1),
    by = c("sub_id", "from", "to")
  ) %>%
  mutate(edge = if_else(is.na(edge), 0, edge))

Schema-based representation

If people were using triad or community schemas/heuristics to inform representation, what would this look like? Using literally the exact same tools that we used to analyze the butterfly network, let’s create some predicted representations.

schema_experts_all <- obs_adjlist_all %>%
  # Memorization
  group_by(sub_id, from) %>%
  mutate(
    mem_value = edge / sum(edge),
    mem_value = if_else(is.nan(mem_value), 0, mem_value)
  ) %>%
  ungroup() %>%
  # Now triads
  left_join(
    obs_adjlist_all %>%
      group_by(sub_id) %>%
      nest() %>%
      mutate(triad = map(data, ~build_rep_triad(.x, "edge"))) %>%
      unnest(triad) %>%
      ungroup() %>%
      select(-c(data, transition_scaling)) %>%
      mutate(triad_value = if_else(is.nan(triad_value), 0, triad_value)),
    by = c("sub_id", "from", "to")
  ) %>%
  # Finally communities
  left_join(
    obs_adjlist_all %>%
      group_by(sub_id) %>%
      nest() %>%
      mutate(comm = map(data, ~build_rep_community(.x, "edge"))) %>%
      unnest(comm) %>%
      ungroup() %>%
      select(-c(data, transition_scaling)),
    by = c("sub_id", "from", "to")
  )

schema_experts_out <- obs_adjlist_out %>%
  # Memorization
  group_by(sub_id, from) %>%
  mutate(
    mem_value = edge / sum(edge),
    mem_value = if_else(is.nan(mem_value), 0, mem_value)
  ) %>%
  ungroup() %>%
  # Now triads
  left_join(
    obs_adjlist_out %>%
      group_by(sub_id) %>%
      nest() %>%
      mutate(triad = map(data, ~build_rep_triad(.x, "edge"))) %>%
      unnest(triad) %>%
      ungroup() %>%
      select(-c(data, transition_scaling)) %>%
      mutate(triad_value = if_else(is.nan(triad_value), 0, triad_value)),
    by = c("sub_id", "from", "to")
  ) %>%
  # Finally communities
  left_join(
    obs_adjlist_out %>%
      group_by(sub_id) %>%
      nest() %>%
      mutate(comm = map(data, ~build_rep_community(.x, "edge"))) %>%
      unnest(comm) %>%
      ungroup() %>%
      select(-c(data, transition_scaling)),
    by = c("sub_id", "from", "to")
  )

schema_experts_in <- obs_adjlist_in %>%
  # Memorization
  group_by(sub_id, from) %>%
  mutate(
    mem_value = edge / sum(edge),
    mem_value = if_else(is.nan(mem_value), 0, mem_value)
  ) %>%
  ungroup() %>%
  # Now triads
  left_join(
    obs_adjlist_in %>%
      group_by(sub_id) %>%
      nest() %>%
      mutate(triad = map(data, ~build_rep_triad(.x, "edge"))) %>%
      unnest(triad) %>%
      ungroup() %>%
      select(-c(data, transition_scaling)) %>%
      mutate(triad_value = if_else(is.nan(triad_value), 0, triad_value)),
    by = c("sub_id", "from", "to")
  ) %>%
  # Finally communities
  left_join(
    obs_adjlist_in %>%
      group_by(sub_id) %>%
      nest() %>%
      mutate(comm = map(data, ~build_rep_community(.x, "edge"))) %>%
      unnest(comm) %>%
      ungroup() %>%
      select(-c(data, transition_scaling)),
    by = c("sub_id", "from", "to")
  )
plot_mem_all <- plot_representation(schema_experts_all, mem_value) +
  ggtitle("Memorization")

plot_triad_all <- plot_representation(schema_experts_all, triad_value) +
  ggtitle("Triad Completion")

plot_comm_all <- plot_representation(schema_experts_all, comm_value) +
  ggtitle("Community Detection")

plot_schemas_all <- (
  plot_choice | plot_mem_all | plot_triad_all | plot_comm_all
) +
  plot_annotation(
    title = "Observations of advice-giving go both ways",
    theme = theme(plot.title = element_text(size = 15, hjust = 0.5))
  )

plot_schemas_all

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "schema_gallery_all.pdf"),
    plot_schemas_all,
    width = 12, height = 4,
    device = cairo_pdf, units = "in", dpi = 300
  )
}
plot_mem_out <- plot_representation(schema_experts_out, mem_value) +
  ggtitle("Memorization")

plot_triad_out <- plot_representation(schema_experts_out, triad_value) +
  ggtitle("Triad Completion")

plot_comm_out <- plot_representation(schema_experts_out, comm_value) +
  ggtitle("Community Detection")

plot_schemas_out <- (
  plot_choice | plot_mem_out | plot_triad_out | plot_comm_out
) +
  plot_annotation(
    title = "Advisees observe advisors' advisors",
    theme = theme(plot.title = element_text(size = 15, hjust = 0.5))
  )

plot_schemas_out

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "schema_gallery_out.pdf"),
    plot_schemas_out,
    width = 12, height = 4,
    device = cairo_pdf, units = "in", dpi = 300
  )
}
plot_mem_in <- plot_representation(schema_experts_in, mem_value) +
  ggtitle("Memorization")

plot_triad_in <- plot_representation(schema_experts_in, triad_value) +
  ggtitle("Triad Completion")

plot_comm_in <- plot_representation(schema_experts_in, comm_value) +
  ggtitle("Community Detection")

plot_schemas_in <- (
  plot_choice | plot_mem_in | plot_triad_in | plot_comm_in
) +
  plot_annotation(
    title = "Advisors observe advisees' advisees",
    theme = theme(plot.title = element_text(size = 15, hjust = 0.5))
  )

plot_schemas_in

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "schema_gallery_in.pdf"),
    plot_schemas_in,
    width = 12, height = 4,
    device = cairo_pdf, units = "in", dpi = 300
  )
}

At the group-level… schemas make frankly terrible predictions, no matter what we assume about observations. Note that if a particular subject is predicted to ask all other managers for advice, the row associated with that subject will be filled with a value close to 1/20=0.05. So we can see that the triad completion strategy predicts that most managers are connected, and the community detection strategy predicts that literally all managers are connected. Neither comes even a little bit close to the actual allocentric network representation.

Successor repesentation

Let’s say people use multistep relational abstraction to represent networks, and let’s use the SR to approximate that kind of abstraction. Using the observations we generated before, let’s create lots of learning “trials” to train the algorithm.

sr_observations_all <- obs_edgelist_all %>%
  # Create simulated "learning trials" to train an asymptotic SR
  expand_grid(rep = 1:100) %>%
  # Randomize "order of trials" per repetition
  group_by(sub_id, rep) %>%
  slice_sample(prop = 1) %>%
  ungroup()

sr_observations_out <- obs_edgelist_out %>%
  expand_grid(rep = 1:100) %>%
  group_by(sub_id, rep) %>%
  slice_sample(prop = 1) %>%
  ungroup()

sr_observations_in <- obs_edgelist_in %>%
  expand_grid(rep = 1:100) %>%
  group_by(sub_id, rep) %>%
  slice_sample(prop = 1) %>%
  ungroup()

And now we can use those to build SRs at different scales. We’ll assume that every subject is using the same successor horizon…

sr_all <- sr_observations_all %>%
  expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
  group_by(sub_id, gamma) %>%
  nest() %>%
  mutate(
    sr = map2(
      .x = data, .y = gamma,
      ~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
    )
  ) %>%
  unnest(sr) %>%
  ungroup() %>%
  select(-data) %>%
  mutate(gamma = gamma * 10) %>%
  pivot_wider(
    names_from = gamma,
    names_prefix = "sr",
    values_from = sr_value
  )

sr_out <- sr_observations_out %>%
  expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
  group_by(sub_id, gamma) %>%
  nest() %>%
  mutate(
    sr = map2(
      .x = data, .y = gamma,
      ~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
    )
  ) %>%
  unnest(sr) %>%
  ungroup() %>%
  select(-data) %>%
  mutate(gamma = gamma * 10) %>%
  pivot_wider(
    names_from = gamma,
    names_prefix = "sr",
    values_from = sr_value
  )

sr_in <- sr_observations_in %>%
  expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
  group_by(sub_id, gamma) %>%
  nest() %>%
  mutate(
    sr = map2(
      .x = data, .y = gamma,
      ~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
    )
  ) %>%
  unnest(sr) %>%
  ungroup() %>%
  select(-data) %>%
  mutate(gamma = gamma * 10) %>%
  pivot_wider(
    names_from = gamma,
    names_prefix = "sr",
    values_from = sr_value
  )

Let’s get a sense for the predictions when the SR is trained on observations that go both ways.

plot_sr1_all <- sr_all %>%
  plot_representation(relation_value = sr1, n_breaks = 4) +
  ggtitle("\u03B3 = 0.1")

plot_sr3_all <- sr_all %>%
  plot_representation(relation_value = sr3) +
  ggtitle("\u03B3 = 0.3")

plot_sr5_all <- sr_all %>%
  plot_representation(relation_value = sr5) +
  ggtitle("\u03B3 = 0.5")

plot_sr7_all <- sr_all %>%
  plot_representation(relation_value = sr7) +
  ggtitle("\u03B3 = 0.7")

plot_sr9_all <- sr_all %>%
  plot_representation(relation_value = sr9) +
  ggtitle("\u03B3 = 0.9")

plot_sr_gallery_all <- (
  plot_choice +
    plot_sr1_all + plot_sr3_all + plot_sr5_all + plot_sr7_all + plot_sr9_all
)

plot_sr_gallery_all

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "sr_gallery_all.pdf"),
    plot_sr_gallery_all,
    width = 12, height = 8,
    device = cairo_pdf, units = "in", dpi = 300
  )
}

And now where advisees observe their advisors’ advisors…

plot_sr1_out <- sr_out %>%
  plot_representation(relation_value = sr1, n_breaks = 4) +
  ggtitle("\u03B3 = 0.1")

plot_sr3_out <- sr_out %>%
  plot_representation(relation_value = sr3) +
  ggtitle("\u03B3 = 0.3")

plot_sr5_out <- sr_out %>%
  plot_representation(relation_value = sr5) +
  ggtitle("\u03B3 = 0.5")

plot_sr7_out <- sr_out %>%
  plot_representation(relation_value = sr7) +
  ggtitle("\u03B3 = 0.7")

plot_sr9_out <- sr_out %>%
  plot_representation(relation_value = sr9) +
  ggtitle("\u03B3 = 0.9")

plot_sr_gallery_out <- (
  plot_choice +
    plot_sr1_out + plot_sr3_out + plot_sr5_out + plot_sr7_out + plot_sr9_out
)

plot_sr_gallery_out

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "sr_gallery_out.pdf"),
    plot_sr_gallery_out,
    width = 12, height = 8,
    device = cairo_pdf, units = "in", dpi = 300
  )
}

And finally where advisors observe their advisees’ advisees…

plot_sr1_in <- sr_in %>%
  plot_representation(relation_value = sr1, n_breaks = 4) +
  ggtitle("\u03B3 = 0.1")

plot_sr3_in <- sr_in %>%
  plot_representation(relation_value = sr3) +
  ggtitle("\u03B3 = 0.3")

plot_sr5_in <- sr_in %>%
  plot_representation(relation_value = sr5) +
  ggtitle("\u03B3 = 0.5")

plot_sr7_in <- sr_in %>%
  plot_representation(relation_value = sr7) +
  ggtitle("\u03B3 = 0.7")

plot_sr9_in <- sr_in %>%
  plot_representation(relation_value = sr9) +
  ggtitle("\u03B3 = 0.9")

plot_sr_gallery_in <- (
  plot_choice +
    plot_sr1_in + plot_sr3_in + plot_sr5_in + plot_sr7_in + plot_sr9_in
)

plot_sr_gallery_in

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "sr_gallery_in.pdf"),
    plot_sr_gallery_in,
    width = 12, height = 8,
    device = cairo_pdf, units = "in", dpi = 300
  )
}

Statistical tests

Okay, now that we have all of the predicted strategies in hand, we’ll want to perform some formal statistical tests to verify that the SR is truly doing the best at explaining subjects’ network representations. Let’s create a dataframe with all of the info we’ll need.

test_dataset_all <- krackhardt_allocentric %>%
  rename(choice = edge) %>%
  left_join(schema_experts_all, by = c("sub_id", "from", "to")) %>%
  left_join(sr_all, by = c("sub_id", "from", "to"))

test_dataset_out <- krackhardt_allocentric %>%
  rename(choice = edge) %>%
  left_join(schema_experts_out, by = c("sub_id", "from", "to")) %>%
  left_join(sr_out, by = c("sub_id", "from", "to"))

test_dataset_in <- krackhardt_allocentric %>%
  rename(choice = edge) %>%
  left_join(schema_experts_in, by = c("sub_id", "from", "to")) %>%
  left_join(sr_in, by = c("sub_id", "from", "to"))

We’ll do all of the statistical tests for the “observations go both ways” models. Note that we can’t actually estimate a model for community detection, as this strategy predicts that everyone is connected to everyone.

test_mem_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + (1 + mem_value | sub_id),
    family = "binomial", data = .
  )

test_triad_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + triad_value + (1 + triad_value | sub_id),
    family = "binomial", data = .
  )

# test_comm_all <- test_dataset_all %>%
#   glmer(
#     choice ~ mem_value + comm_value + (1 + comm_value | sub_id),
#     family = "binomial", data = .
#   )

test_sr1_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr1 + (1 + sr1 | sub_id),
    family = "binomial", data = .
  )

test_sr2_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr2 + (1 + sr2 | sub_id),
    family = "binomial", data = .
  )

test_sr3_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr3 + (1 + sr3 | sub_id),
    family = "binomial", data = .
  )

test_sr4_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr4 + (1 + sr4 | sub_id),
    family = "binomial", data = .
  )

test_sr5_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr5 + (1 + sr5 | sub_id),
    family = "binomial", data = .
  )

test_sr6_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr6 + (1 + sr6 | sub_id),
    family = "binomial", data = .
  )

test_sr7_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
    family = "binomial", data = .
  )

test_sr8_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr8 + (1 + sr8 | sub_id),
    family = "binomial", data = .
  )

test_sr9_all <- test_dataset_all %>%
  glmer(
    choice ~ mem_value + sr9 + (1 + sr9 | sub_id),
    family = "binomial", data = .
  )

Moving on to the “advisees observe advisors’ advisors” models.

test_mem_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + (1 + mem_value | sub_id),
    family = "binomial", data = .
  )

test_triad_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + triad_value + (1 + triad_value | sub_id),
    family = "binomial", data = .
  )

test_comm_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + comm_value + (1 + comm_value | sub_id),
    family = "binomial", data = .
  )

test_sr1_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr1 + (1 + sr1 | sub_id),
    family = "binomial", data = .
  )

test_sr2_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr2 + (1 + sr2 | sub_id),
    family = "binomial", data = .
  )

test_sr3_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr3 + (1 + sr3 | sub_id),
    family = "binomial", data = .
  )

test_sr4_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr4 + (1 + sr4 | sub_id),
    family = "binomial", data = .
  )

test_sr5_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr5 + (1 + sr5 | sub_id),
    family = "binomial", data = .
  )

test_sr6_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr6 + (1 + sr6 | sub_id),
    family = "binomial", data = .
  )

test_sr7_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
    family = "binomial", data = .
  )

test_sr8_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr8 + (1 + sr8 | sub_id),
    family = "binomial", data = .
  )

test_sr9_out <- test_dataset_out %>%
  glmer(
    choice ~ mem_value + sr9 + (1 + sr9 | sub_id),
    family = "binomial", data = .
  )

Finally, the “advisors observe advisees’ advisees” models. Once again, we can’t estimate a model for community detection, as this strategy predicts that everyone is connected to everyone.

test_mem_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + (1 + mem_value | sub_id),
    family = "binomial", data = .
  )

test_triad_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + triad_value + (1 + triad_value | sub_id),
    family = "binomial", data = .
  )

# test_comm_in <- test_dataset_in %>%
#   glmer(
#     choice ~ mem_value + comm_value + (1 + comm_value | sub_id),
#     family = "binomial", data = .
#   )

test_sr1_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr1 + (1 + sr1 | sub_id),
    family = "binomial", data = .
  )

test_sr2_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr2 + (1 + sr2 | sub_id),
    family = "binomial", data = .
  )

test_sr3_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr3 + (1 + sr3 | sub_id),
    family = "binomial", data = .
  )

test_sr4_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr4 + (1 + sr4 | sub_id),
    family = "binomial", data = .
  )

test_sr5_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr5 + (1 + sr5 | sub_id),
    family = "binomial", data = .
  )

test_sr6_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr6 + (1 + sr6 | sub_id),
    family = "binomial", data = .
  )

test_sr7_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
    family = "binomial", data = .
  )

test_sr8_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr8 + (1 + sr8 | sub_id),
    family = "binomial", data = .
  )

test_sr9_in <- test_dataset_in %>%
  glmer(
    choice ~ mem_value + sr9 + (1 + sr9 | sub_id),
    family = "binomial", data = .
  )

Of all of these models, which has the “best” fit, based on BIC?

# Which has the best "goodness-of-fit"?
goodness_of_fit <- bind_rows(
  # All: goes both ways
  glance(test_mem_all) %>% mutate(model = "mem_all"),
  glance(test_triad_all) %>% mutate(model = "triad_all"),
  glance(test_sr1_all) %>% mutate(model = "sr1_all"),
  glance(test_sr2_all) %>% mutate(model = "sr2_all"),
  glance(test_sr3_all) %>% mutate(model = "sr3_all"),
  glance(test_sr4_all) %>% mutate(model = "sr4_all"),
  glance(test_sr5_all) %>% mutate(model = "sr5_all"),
  glance(test_sr6_all) %>% mutate(model = "sr6_all"),
  glance(test_sr7_all) %>% mutate(model = "sr7_all"),
  glance(test_sr8_all) %>% mutate(model = "sr8_all"),
  glance(test_sr9_all) %>% mutate(model = "sr9_all"),
  # Out: advisors of advisors
  glance(test_mem_out) %>% mutate(model = "mem_out"),
  glance(test_triad_out) %>% mutate(model = "triad_out"),
  glance(test_comm_out) %>% mutate(model = "comm_out"),
  glance(test_sr1_out) %>% mutate(model = "sr1_out"),
  glance(test_sr2_out) %>% mutate(model = "sr2_out"),
  glance(test_sr3_out) %>% mutate(model = "sr3_out"),
  glance(test_sr4_out) %>% mutate(model = "sr4_out"),
  glance(test_sr5_out) %>% mutate(model = "sr5_out"),
  glance(test_sr6_out) %>% mutate(model = "sr6_out"),
  glance(test_sr7_out) %>% mutate(model = "sr7_out"),
  glance(test_sr8_out) %>% mutate(model = "sr8_out"),
  glance(test_sr9_out) %>% mutate(model = "sr9_out"),
  # In: advisees of advisees
  glance(test_mem_in) %>% mutate(model = "mem_in"),
  glance(test_triad_in) %>% mutate(model = "triad_in"),
  glance(test_sr1_in) %>% mutate(model = "sr1_in"),
  glance(test_sr2_in) %>% mutate(model = "sr2_in"),
  glance(test_sr3_in) %>% mutate(model = "sr3_in"),
  glance(test_sr4_in) %>% mutate(model = "sr4_in"),
  glance(test_sr5_in) %>% mutate(model = "sr5_in"),
  glance(test_sr6_in) %>% mutate(model = "sr6_in"),
  glance(test_sr7_in) %>% mutate(model = "sr7_in"),
  glance(test_sr8_in) %>% mutate(model = "sr8_in"),
  glance(test_sr9_in) %>% mutate(model = "sr9_in"),
) %>%
  select(model, everything()) %>%
  arrange(BIC) %>%
  # Make this a little more human-readable
  separate(model, into = c("model", "direction")) %>%
  mutate(
    direction = case_when(
      direction == "out" ~ "advisee observes advisor of advisor",
      direction == "in" ~ "advisor observes advisee of advisee",
      direction == "all" ~ "both ways"
    )
  )

goodness_of_fit %>%
  mutate(
    model = fct_relevel(
      model,
      "sr1", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7", "sr8", "sr9",
      "mem", "triad", "comm"
    )
  ) %>%
  ggplot(aes(x = model, y = BIC, color = direction)) +
  gg +
  geom_point() +
  ggtitle("Model goodness-of-fit") +
  theme(legend.position = "bottom")

goodness_of_fit %>%
  kable()
model direction nobs sigma logLik AIC BIC deviance df.residual
sr7 advisee observes advisor of advisor 8400 1 -4363.029 8738.058 8780.274 8565.413 8394
sr8 advisee observes advisor of advisor 8400 1 -4363.853 8739.706 8781.922 8566.508 8394
sr6 advisee observes advisor of advisor 8400 1 -4369.466 8750.931 8793.147 8580.404 8394
sr9 advisee observes advisor of advisor 8400 1 -4375.204 8762.408 8804.624 8592.060 8394
sr5 advisee observes advisor of advisor 8400 1 -4379.140 8770.281 8812.497 8602.266 8394
sr4 advisee observes advisor of advisor 8400 1 -4389.390 8790.781 8832.996 8625.097 8394
sr8 both ways 8400 1 -4398.735 8809.469 8851.685 8657.019 8394
sr7 both ways 8400 1 -4398.873 8809.746 8851.962 8657.895 8394
sr3 advisee observes advisor of advisor 8400 1 -4398.903 8809.805 8852.021 8646.054 8394
sr6 both ways 8400 1 -4403.292 8818.583 8860.799 8668.298 8394
sr9 both ways 8400 1 -4406.178 8824.357 8866.573 8673.713 8394
sr2 advisee observes advisor of advisor 8400 1 -4407.193 8826.387 8868.603 8664.134 8394
sr5 both ways 8400 1 -4409.244 8830.487 8872.703 8681.930 8394
sr1 advisee observes advisor of advisor 8400 1 -4414.189 8840.378 8882.594 8679.243 8394
sr4 both ways 8400 1 -4415.308 8842.615 8884.831 8695.618 8394
sr3 both ways 8400 1 -4420.912 8853.824 8896.040 8708.120 8394
triad advisee observes advisor of advisor 8400 1 -4422.288 8856.576 8898.791 8721.435 8394
sr2 both ways 8400 1 -4425.886 8863.773 8905.989 8719.092 8394
sr1 both ways 8400 1 -4430.221 8872.442 8914.658 8728.545 8394
triad both ways 8400 1 -4431.553 8875.106 8917.322 8740.564 8394
mem advisee observes advisor of advisor 8400 1 -4444.995 8899.991 8935.171 8763.004 8395
mem both ways 8400 1 -4452.356 8914.713 8949.893 8775.496 8395
comm advisee observes advisor of advisor 8400 1 -4461.317 8934.634 8976.850 8821.487 8394
mem advisor observes advisee of advisee 8400 1 -4590.630 9191.259 9226.439 9024.731 8395
sr7 advisor observes advisee of advisee 8400 1 -4591.253 9194.506 9236.722 9021.134 8394
triad advisor observes advisee of advisee 8400 1 -4591.808 9195.615 9237.831 9044.740 8394
sr6 advisor observes advisee of advisee 8400 1 -4591.998 9195.997 9238.213 9024.658 8394
sr8 advisor observes advisee of advisee 8400 1 -4593.417 9198.834 9241.050 9024.487 8394
sr5 advisor observes advisee of advisee 8400 1 -4594.073 9200.146 9242.362 9031.037 8394
sr4 advisor observes advisee of advisee 8400 1 -4596.625 9205.251 9247.467 9038.234 8394
sr3 advisor observes advisee of advisee 8400 1 -4599.254 9210.508 9252.724 9045.352 8394
sr9 advisor observes advisee of advisee 8400 1 -4600.464 9212.929 9255.145 9040.442 8394
sr2 advisor observes advisee of advisee 8400 1 -4601.778 9215.556 9257.772 9052.026 8394
sr1 advisor observes advisee of advisee 8400 1 -4604.117 9220.234 9262.450 9058.124 8394

Let’s take a look at the best-fitting model estimates:

test_sr7_out %>%
  tidy(conf.int = TRUE) %>%
  kable()
effect group term estimate std.error statistic p.value conf.low conf.high
fixed NA (Intercept) -1.8725110 0.1852784 -10.106474 0 -2.235650 -1.509372
fixed NA mem_value 3.5286019 0.4025315 8.766027 0 2.739655 4.317549
fixed NA sr7 14.7453961 2.3390595 6.303985 0 10.160924 19.329868
ran_pars sub_id sd__(Intercept) 0.8095989 NA NA NA NA NA
ran_pars sub_id cor__(Intercept).sr7 -0.2827640 NA NA NA NA NA
ran_pars sub_id sd__sr7 9.5523177 NA NA NA NA NA
vif(test_sr7_out)
## mem_value       sr7 
##  1.081353  1.081353

SR centrality

Can the best-fitting SR explain an individual’s perceptions of other network members’ centrality?

sr_centrality <- sr_out %>%
  # SR centrality from best variant
  filter(from != to) %>%
  group_by(sub_id, node_id = to) %>%
  summarise(sr_centrality = mean(sr7), .groups = "drop") %>%
  # Perceived centrality
  left_join(
    krackhardt_allocentric %>%
      group_by(sub_id, node_id = to) %>%
      summarise(perceived_centrality = mean(edge), .groups = "drop"),
    by = c("sub_id", "node_id")
  )

To answer this, we’ll do a random-effects analysis where we take each individual’s idiosyncratic mental representation of their network, then rank-correlate it with the SR’s individual-level predictions.

sr_centrality_corr <- sr_centrality %>%
  group_by(sub_id) %>%
  nest() %>%
  mutate(
    spearman = map_dbl(
      .x = data,
      .f = ~with(
        .x, cor(sr_centrality, perceived_centrality, method = "spearman")
      )
    )
  ) %>%
  ungroup() %>%
  select(-data)

sr_centrality_corr %>%
  mutate(spearman = tanh(spearman)) %>%
  select(spearman) %>%
  deframe() %>%
  t.test() %>%
  tidy() %>%
  kable(
    caption = str_c(
      "t-test of the average Spearman correlation between perceived and ",
      "SR-predicted centrality (z-transformed)"
    )
  )
t-test of the average Spearman correlation between perceived and SR-predicted centrality (z-transformed)
estimate statistic p.value parameter conf.low conf.high method alternative
0.3942865 14.28888 0 20 0.3367265 0.4518465 One Sample t-test two.sided
sr_centrality_corr %>%
  summarise(mean_spearman = mean(spearman)) %>%
  kable()
mean_spearman
0.4257979

Let’s try to visualize these results in an intuitive format.

plot_sr_centrality_group <- sr_centrality %>%
  # Get each subject's rank-ordered perceived and SR-predicted centrality
  group_by(sub_id) %>%
  mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
  ungroup() %>%
  # Average across subjects to get group-level results
  group_by(node_id) %>%
  summarise(across(ends_with("_centrality"), mean)) %>%
  # For color-coding two pairs of managers with equivalent degree centrality,
  # but different perceived centrality
  mutate(
    colorcode = case_when(
      node_id %in% c(1, 7) ~ "a",
      node_id %in% c(18, 21) ~ "b"
    )
  ) %>%
  ggplot(aes(x=perceived_centrality, y=sr_centrality)) +
  gg +
  geom_smooth(method = "lm", se = FALSE, color = "black") +
  geom_label(aes(label = node_id, fill = colorcode), show.legend = FALSE) +
  scale_fill_manual(values = c("#a6cee3", "#b2df8a"), na.value = "grey95") +
  scale_x_continuous(name = "Perceived centrality (rank-ordered)") +
  scale_y_continuous(name = "SR centrality (rank-ordered)") +
  ggtitle("Perceived vs Successor Centrality (Group-Level)")

plot_sr_centrality_group
## `geom_smooth()` using formula = 'y ~ x'

plot_sr_centrality_individual <- sr_centrality %>%
  # Get each subject's rank-ordered perceived and SR-predicted centrality
  group_by(sub_id) %>%
  mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
  ungroup() %>%
  # Formatting for plotting
  pivot_longer(
    ends_with("_centrality"),
    names_to = "metric",
    values_to = "centrality"
  ) %>%
  mutate(
    node_id = factor(node_id),
    sub_id = str_pad(sub_id, width = 2, side = "left", pad = "0"),
    sub_id = str_c("Manager ", sub_id)
  ) %>%
  ggplot(aes(x=node_id, y=centrality, fill=metric)) +
  facet_wrap(~sub_id, nrow = 3) +
  geom_col(position = "identity", color = "black", alpha = 0.5) +
  coord_polar() +
  scale_fill_viridis_d(
    name = "Centrality",
    labels = c("Perceived (Empirical)", "Successor Representation (Simulated)")
  ) +
  ggtitle("Perceived vs Successor Centrality (Individual-Level)") +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 13),
    plot.subtitle = element_text(hjust = 0.5, size = 11),
    panel.grid.minor = element_blank(),
    panel.spacing = unit(0.75, "lines"),
    legend.box.spacing = unit(0.5, "lines"),
    legend.margin = margin(c(0, 0, 0, 0), unit = "lines"),
    legend.position = "bottom",
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank()
  )

plot_sr_centrality_individual

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "sr_centrality_individual_standard.pdf"),
    plot = plot_sr_centrality_individual,
    width = 12, height = 8,
    device = cairo_pdf, units = "in", dpi = 300
  )
}

We’re particularly interested in the manager pairs 1-7 and 18-21. On an individual-by-individual basis, does the model correctly predict, in each pair, which manager is represented as being more central? We’ll do a prevalence test to see whether the model made correct predictions for significantly greater than 50% of subjects.

sr_centrality %>%
  # Find and retain only relevant node-pairs
  mutate(
    pair_id = case_when(
      node_id %in% c(1, 7) ~ "1-7",
      node_id %in% c(18, 21) ~ "18-21"
    )
  ) %>%
  drop_na() %>%
  # Whichever manager is represented as being more central in each node-pair,
  # does the model make a correct prediction?
  group_by(sub_id, pair_id) %>%
  mutate(
    across(
      c(sr_centrality, perceived_centrality),
      ~.x - first(.x)
    )
  ) %>%
  filter(node_id %in% c(7, 21)) %>%
  summarise(
    correct = sr_centrality * perceived_centrality > 0,
    .groups = "drop"
  ) %>%
  # Tally correct predictions
  count(pair_id, correct) %>%
  # Prevalence test
  filter(correct) %>%
  split(.$pair_id) %>%
  map_dfr(
    .f = ~.x %>%
      select(n) %>%
      deframe() %>%
      binom.test(x = ., n = 21, p = 0.5, alternative = "greater") %>%
      tidy(),
    .id = "pair_id"
  ) %>%
  kable(caption = "Prevalence test (> 50%)")
Prevalence test (> 50%)
pair_id estimate statistic p.value parameter conf.low conf.high method alternative
1-7 0.7142857 15 0.0391769 21 0.5126112 1 Exact binomial test greater
18-21 0.8571429 18 0.0007448 21 0.6707890 1 Exact binomial test greater

We’d previously noted that betweenness seems to track discrepancies between a manager’s true versus perceived centrality. Does SR centrality track with betweenness? The loess curve suggests the relationship is nonlinear, but there is a strongly significant rank correlation between the two.

sr_centrality %>%
  group_by(name = node_id) %>%
  summarise(sr_centrality = mean(sr_centrality)) %>%
  left_join(centrality_differences) %>%
  ggplot(aes(x=sr_centrality, y=Betweenness)) +
  gg +
  geom_smooth(method = "loess", se = FALSE) +
  geom_label(aes(label = name)) +
  xlab("Successor Representation \u03B3 = 0.7")
## Joining with `by = join_by(name)`
## `geom_smooth()` using formula = 'y ~ x'

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "centrality_sr_vs_betweenness.pdf"),
    width = 6, height = 4,
    device = cairo_pdf, units = "in", dpi = 300
  )
}
## `geom_smooth()` using formula = 'y ~ x'
sr_centrality %>%
  group_by(name = node_id) %>%
  summarise(sr_centrality = mean(sr_centrality)) %>%
  left_join(centrality_differences) %>%
  with(cor.test(Betweenness, sr_centrality, method = "spearman", exact = FALSE)) %>%
  tidy() %>%
  kable(caption = "Betweenness vs SR gamma 0.7")
## Joining with `by = join_by(name)`
Betweenness vs SR gamma 0.7
estimate statistic p.value method alternative
0.8948052 162 0 Spearman’s rank correlation rho two.sided

Company leadership

So far, we have not provided the model with any privileged knowledge about the company’s senior leadership hierarchy. Yet, using observations constrained by the network structure, the model has identified most of the company’s leadership anyways.

The CEO is coded as node 7, and the four Vice Presidents are coded as 2, 14, 18, and 21. We see clear evidence that the model identifies nodes 2, 7, 18, and 21 as being central figures, but the model makes conspicuously incorrect predictions about manager 14.

Could the model in principle do a better job at identifying manager 14 as a central network member? To test this, we’ll make one additional assumption about managers’ observations: they observe the senior leadership twice as much as other network members.

sr_observations_leadership <- obs_edgelist_out %>%
  # Double-count CEO and VPs
  bind_rows(
    obs_edgelist_out %>%
      filter(from %in% c(2, 7, 14, 18, 21) | to %in% c(2, 7, 14, 18, 21))
  ) %>%
  expand_grid(rep = 1:100) %>%
  group_by(sub_id, rep) %>%
  slice_sample(prop = 1) %>%
  ungroup()

sr_leadership <- sr_observations_leadership %>%
  expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
  group_by(sub_id, gamma) %>%
  nest() %>%
  mutate(
    sr = map2(
      .x = data, .y = gamma,
      ~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
    )
  ) %>%
  unnest(sr) %>%
  ungroup() %>%
  select(-data) %>%
  mutate(gamma = gamma * 10) %>%
  pivot_wider(
    names_from = gamma,
    names_prefix = "sr",
    values_from = sr_value
  )

We’ll test whether the model goodness-of-fit is better at \(\gamma = 0.7\), which was the best-fitting model from before:

test_sr7_leadership <- krackhardt_allocentric %>%
  rename(choice = edge) %>%
  left_join(schema_experts_out, by = c("sub_id", "from", "to")) %>%
  left_join(sr_leadership, by = c("sub_id", "from", "to")) %>%
  glmer(
    choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
    family = "binomial", data = .
  )

bind_rows(
  glance(test_sr7_out) %>% mutate(model = "sr7 standard"),
  glance(test_sr7_leadership) %>% mutate(model = "sr7 leadership 2x")
) %>%
  kable()
nobs sigma logLik AIC BIC deviance df.residual model
8400 1 -4363.029 8738.058 8780.274 8565.413 8394 sr7 standard
8400 1 -4301.586 8615.172 8657.388 8443.772 8394 sr7 leadership 2x
sr_centrality_leadership <- sr_leadership %>%
  # SR centrality from best variant
  filter(from != to) %>%
  group_by(sub_id, node_id = to) %>%
  summarise(sr_centrality = mean(sr7), .groups = "drop") %>%
  # Perceived centrality
  left_join(
    krackhardt_allocentric %>%
      group_by(sub_id, node_id = to) %>%
      summarise(perceived_centrality = mean(edge), .groups = "drop"),
    by = c("sub_id", "node_id")
  )

sr_centrality_corr_leadership <- sr_centrality_leadership %>%
  group_by(sub_id) %>%
  nest() %>%
  mutate(
    spearman = map_dbl(
      .x = data,
      .f = ~with(
        .x, cor(
          sr_centrality, perceived_centrality, method = "spearman"
        )
      )
    )
  ) %>%
  ungroup() %>%
  select(-data)

sr_centrality_corr_leadership %>%
  mutate(spearman = tanh(spearman)) %>%
  select(spearman) %>%
  deframe() %>%
  t.test() %>%
  tidy() %>%
  kable(
    caption = str_c(
      "t-test of the average Spearman correlation between perceived and ",
      "SR-predicted centrality (z-transformed)"
    )
  )
t-test of the average Spearman correlation between perceived and SR-predicted centrality (z-transformed)
estimate statistic p.value parameter conf.low conf.high method alternative
0.4581988 16.76413 0 20 0.4011851 0.5152126 One Sample t-test two.sided
sr_centrality_corr_leadership %>%
  summarise(mean_spearman = mean(spearman)) %>%
  kable()
mean_spearman
0.5059155
plot_sr_centrality_group_leadership <- sr_centrality_leadership %>%
  # Get each subject's rank-ordered perceived and SR-predicted centrality
  group_by(sub_id) %>%
  mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
  ungroup() %>%
  # Average across subjects to get group-level results
  group_by(node_id) %>%
  summarise(across(ends_with("_centrality"), mean)) %>%
  # For color-coding two pairs of managers with equivalent degree centrality,
  # but different perceived centrality
  mutate(
    colorcode = case_when(
      node_id %in% c(1, 7) ~ "a",
      node_id %in% c(18, 21) ~ "b"
    )
  ) %>%
  ggplot(aes(x=perceived_centrality, y=sr_centrality)) +
  gg +
  geom_smooth(method = "lm", se = FALSE, color = "black") +
  geom_label(aes(label = node_id, fill = colorcode), show.legend = FALSE) +
  scale_fill_manual(values = c("#a6cee3", "#b2df8a"), na.value = "grey95") +
  scale_x_continuous(name = "Perceived centrality (rank-ordered)") +
  scale_y_continuous(name = "SR centrality (rank-ordered)") +
  ggtitle("Perceived vs Successor Centrality (Group-Level)")

plot_sr_centrality_group_leadership
## `geom_smooth()` using formula = 'y ~ x'

plot_sr_centrality_individual_leadership <- sr_centrality_leadership %>%
  # Get each subject's rank-ordered perceived and SR-predicted centrality
  group_by(sub_id) %>%
  mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
  ungroup() %>%
  # Formatting for plotting
  pivot_longer(
    ends_with("_centrality"),
    names_to = "metric",
    values_to = "centrality"
  ) %>%
  mutate(
    node_id = factor(node_id),
    sub_id = str_pad(sub_id, width = 2, side = "left", pad = "0"),
    sub_id = str_c("Manager ", sub_id)
  ) %>%
  ggplot(aes(x=node_id, y=centrality, fill=metric)) +
  facet_wrap(~sub_id, nrow = 3) +
  geom_col(position = "identity", color = "black", alpha = 0.5) +
  coord_polar() +
  scale_fill_viridis_d(
    name = "Centrality",
    labels = c("Perceived (Empirical)", "Successor Representation (Simulated)")
  ) +
  ggtitle("Perceived vs Successor Centrality (Individual-Level)") +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 13),
    plot.subtitle = element_text(hjust = 0.5, size = 11),
    panel.grid.minor = element_blank(),
    panel.spacing = unit(0.75, "lines"),
    legend.box.spacing = unit(0.5, "lines"),
    legend.margin = margin(c(0, 0, 0, 0), unit = "lines"),
    legend.position = "bottom",
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank()
  )

plot_sr_centrality_individual_leadership

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "sr_centrality_group_leadership.pdf"),
    plot = plot_sr_centrality_group_leadership,
    width = 6, height = 4,
    device = cairo_pdf, units = "in", dpi = 300
  )
  
  ggsave(
    here("outputs", "07-krackhardt", "sr_centrality_individual_leadership.pdf"),
    plot = plot_sr_centrality_individual_leadership,
    width = 12, height = 8,
    device = cairo_pdf, units = "in", dpi = 300
  )
}
## `geom_smooth()` using formula = 'y ~ x'

Figures for paper

network_for_paper <- krackhardt_g %>%
  mutate(
    Degree = centrality_degree(mode = "in"),
    node_colorcode = case_when(
      name %in% c(1, 7) ~ "a",
      name %in% c(18, 21) ~ "b"
    )
  ) %>%
  # To clean up some of the overplotting
  activate("edges") %>%
  mutate(
    edge_colorcode = case_when(
      from %in% c(1, 7) | to %in% c(1, 7) ~ "a",
      from %in% c(18, 21) | to %in% c(18, 21) ~ "b"
    )
  ) %>%
  # Plot the "ground truth" network
  ggraph(layout = "stress") +
  geom_edge_link(
    aes(
      start_cap = label_rect(node1.name, padding = margin(15, 15, 15, 15)),
      end_cap = label_rect(node2.name, padding = margin(15, 15, 15, 15)),
      color = edge_colorcode
    ),
    arrow = arrow(length = unit(5, "pt"), type = "closed"),
    show.legend = FALSE
  ) +
  geom_node_label(
    aes(label = name, size = Degree, fill = node_colorcode),
    show.legend = FALSE
  ) +
  scale_size(range = c(3, 10)) +
  scale_fill_manual(values = c("#a6cee3", "#b2df8a"), na.value = "grey95") +
  scale_edge_color_manual(
    values = c("#1f78b4", "#33a02c"), na.value = "grey80"
  ) +
  ggtitle("Advice Network (Krackhardt 1987)") +
  theme(
    panel.background = element_blank(),
    strip.background = element_blank(),
    panel.border = element_blank(),
    axis.title = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    plot.title = element_text(hjust = 0.5, size = 13),
    strip.text = element_text(hjust = 0.5, size = 13),
    legend.position = "bottom"
  )

network_for_paper

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "network_graph.pdf"),
    plot = network_for_paper,
    width = 12, height = 5,
    device = cairo_pdf, units = "in", dpi = 300
  )
}
representation_for_paper <- (
  (plot_choice + ggtitle("Perceived (Empirical)")) |
    plot_sr7_out + ggtitle("Successor Rep. \u03B3 = 0.7 (Simulated)")
) +
  plot_annotation(
    title = "Network Representation",
    theme = theme(plot.title = element_text(size = 13, hjust = 0.5))
  )

representation_for_paper

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "representation.pdf"),
    plot = representation_for_paper,
    width = 12, height = 5,
    device = cairo_pdf, units = "in", dpi = 300
  )
}
centrality_individual_for_paper <- sr_centrality %>%
  filter(sub_id %in% c(17, 19)) %>%
  # Get each subject's rank-ordered perceived and SR-predicted centrality
  group_by(sub_id) %>%
  mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
  ungroup() %>%
  # Formatting for plotting
  pivot_longer(
    ends_with("_centrality"),
    names_to = "metric",
    values_to = "centrality"
  ) %>%
  mutate(
    node_id = factor(node_id),
    sub_id = str_pad(sub_id, width = 2, side = "left", pad = "0"),
    sub_id = str_c("Manager ", sub_id)
  ) %>%
  ggplot(aes(x=node_id, y=centrality, fill=metric)) +
  facet_wrap(~sub_id) +
  geom_col(position = "identity", color = "black", alpha = 0.5) +
  coord_polar() +
  scale_fill_viridis_d(
    name = "Centrality",
    labels = c("Perceived (Empirical)", "Successor Rep. (Simulated)")
  ) +
  ggtitle("Individual-Level") +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 13),
    plot.subtitle = element_text(hjust = 0.5, size = 11),
    panel.grid.minor = element_blank(),
    panel.spacing = unit(0.75, "lines"),
    legend.box.spacing = unit(0.5, "lines"),
    legend.margin = margin(c(0, 0, 0, 0), unit = "lines"),
    legend.position = "bottom",
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank()
  )

centrality_for_paper <- (
  (
    plot_sr_centrality_group +
      ggtitle("Group-Level") +
      scale_y_continuous(name = "Successor Rep. centrality (rank-ordered)")
  ) |
    centrality_individual_for_paper
) +
  plot_annotation(
    title = "Perceived vs Successor Centrality",
    theme = theme(plot.title = element_text(size = 13, hjust = 0.5))
  )
## Scale for y is already present.
## Adding another scale for y, which will replace the existing scale.
centrality_for_paper
## `geom_smooth()` using formula = 'y ~ x'

if (knitting) {
  ggsave(
    here("outputs", "07-krackhardt", "centrality.pdf"),
    plot = centrality_for_paper,
    width = 12, height = 5,
    device = cairo_pdf, units = "in", dpi = 300
  )
}
## `geom_smooth()` using formula = 'y ~ x'

Save data

It was a bit of a pain getting the raw data into shape, so we’ll save the cleaned versions for posterity.

if (knitting) {
  krackhardt_egocentric %>%
    write_csv(here("data", "krackhardt", "clean_egocentric.csv"))
  
  krackhardt_allocentric %>%
    rename(choice = edge) %>%
    write_csv(here("data", "krackhardt", "clean_allocentric.csv"))
}

Session info

sessionInfo()
## R version 4.3.1 (2023-06-16)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Ventura 13.5.2
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: America/New_York
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] broom.mixed_0.2.9.4 lmerTest_3.1-3      lme4_1.1-34        
##  [4] Matrix_1.6-1        patchwork_1.1.3     ggraph_2.1.0       
##  [7] tidygraph_1.2.3     here_1.0.1          lubridate_1.9.2    
## [10] forcats_1.0.0       stringr_1.5.0       dplyr_1.1.2        
## [13] purrr_1.0.2         readr_2.1.4         tidyr_1.3.0        
## [16] tibble_3.2.1        ggplot2_3.4.3       tidyverse_2.0.0    
## 
## loaded via a namespace (and not attached):
##  [1] tidyselect_1.2.0    viridisLite_0.4.2   farver_2.1.1       
##  [4] viridis_0.6.4       fastmap_1.1.1       tweenr_2.0.2       
##  [7] digest_0.6.33       timechange_0.2.0    lifecycle_1.0.3    
## [10] magrittr_2.0.3      compiler_4.3.1      rlang_1.1.1        
## [13] sass_0.4.7          tools_4.3.1         igraph_1.5.1       
## [16] utf8_1.2.3          yaml_2.3.7          knitr_1.43         
## [19] labeling_0.4.2      graphlayouts_1.0.0  bit_4.0.5          
## [22] abind_1.4-5         withr_2.5.0         numDeriv_2016.8-1.1
## [25] grid_4.3.1          polyclip_1.10-4     fansi_1.0.4        
## [28] colorspace_2.1-0    future_1.33.0       globals_0.16.2     
## [31] scales_1.2.1        MASS_7.3-60         cli_3.6.1          
## [34] crayon_1.5.2        rmarkdown_2.24      generics_0.1.3     
## [37] tzdb_0.4.0          minqa_1.2.5         cachem_1.0.8       
## [40] ggforce_0.4.1       splines_4.3.1       parallel_4.3.1     
## [43] vctrs_0.6.3         boot_1.3-28.1       jsonlite_1.8.7     
## [46] carData_3.0-5       car_3.1-2           hms_1.1.3          
## [49] bit64_4.0.5         ggrepel_0.9.3       listenv_0.9.0      
## [52] jquerylib_0.1.4     glue_1.6.2          parallelly_1.36.0  
## [55] nloptr_2.0.3        codetools_0.2-19    stringi_1.7.12     
## [58] gtable_0.3.3        munsell_0.5.0       pillar_1.9.0       
## [61] furrr_0.3.1         htmltools_0.5.6     R6_2.5.1           
## [64] rprojroot_2.0.3     vroom_1.6.3         evaluate_0.21      
## [67] lattice_0.21-8      highr_0.10          backports_1.4.1    
## [70] broom_1.0.5         bslib_0.5.1         Rcpp_1.0.11        
## [73] gridExtra_2.3       nlme_3.1-162        mgcv_1.8-42        
## [76] xfun_0.40           fs_1.6.3            pkgconfig_2.0.3
LS0tCnRpdGxlOiAiUmVhbmFseXplIEtyYWNraGFyZHQgMTk4NyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKLS0tCgpJbiBoaXMgMTk4NyBwYXBlciAoQ29nbml0aXZlIFNvY2lhbCBTdHJ1Y3R1cmVzKSwgS3JhY2toYXJkdCBpbmNsdWRlcyBkYXRhIGZyb20gYSAyMS1tZW1iZXIgbmV0d29yayBvZiBtYW5hZ2VycyAoYWxsIG1hbGUpIGF0IGEgdGVjaCBtYW51ZmFjdHVyaW5nIGNvbXBhbnkuIFRoZXNlIGRhdGEgaW5jbHVkZSBub3Qgb25seSBlZ29jZW50cmljIHJlcG9ydHMgKHRoZXNlIGFyZSB0aGUgcGVvcGxlICpJKiBnbyB0byBmb3IgYWR2aWNlKSwgYnV0IGFsc28gYWxsb2NlbnRyaWMgcmVwb3J0cyAoSSB0aGluayBKb2huIG9mdGVuIGFza3MgQmlsbCBmb3IgYWR2aWNlKS4gV2UgY2FuIHRyeSB0ZXN0aW5nIHdoZXRoZXIgbXVsdGlzdGVwIHJlbGF0aW9uYWwgYWJzdHJhY3Rpb24gZXhwbGFpbnMgdGhlIHN1YmplY3RzJyBhbGxvY2VudHJpYyBiZWxpZWZzIGluIHRoaXMgZGF0YXNldC4KCiMgU2V0dXAKCmBgYHtyIHNldHVwfQojIFNldCBhIHJhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoc3VtKHV0ZjhUb0ludCgia3JhY2toYXJkdCIpKSkKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkodGlkeWdyYXBoKQpsaWJyYXJ5KGdncmFwaCkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobG1lNCkKbGlicmFyeShsbWVyVGVzdCkKbGlicmFyeShicm9vbS5taXhlZCkKCmthYmxlIDwtIGtuaXRyOjprYWJsZQp2aWYgPC0gY2FyOjp2aWYKCmtuaXR0aW5nIDwtIGtuaXRyOjppc19odG1sX291dHB1dCgpCgppZiAoa25pdHRpbmcpIHsKICAjIENyZWF0ZSBkaXJlY3RvcmllcyBmb3Igc2F2aW5nIHN0dWZmCiAgaWYgKCFkaXIuZXhpc3RzKGhlcmUoIm91dHB1dHMiKSkpIHsKICAgIGRpci5jcmVhdGUoaGVyZSgib3V0cHV0cyIpKQogIH0KICAKICBpZiAoIWRpci5leGlzdHMoaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IikpKSB7CiAgICBkaXIuY3JlYXRlKGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIpKQogIH0KfQoKIyBQdWxsIGluIHNvbWUgbW9kZWxpbmcgdG9vbHMKc291cmNlKGhlcmUoImNvZGUiLCAidXRpbHMiLCAicmVwcmVzZW50YXRpb25fdXRpbHMuUiIpKQpzb3VyY2UoaGVyZSgiY29kZSIsICJ1dGlscyIsICJuZXR3b3JrX3V0aWxzLlIiKSkKCmdnIDwtIGxpc3QoCiAgdGhlbWVfYncoKSwKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMyksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTEpLAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjc1LCAibGluZXMiKSwKICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oYygwLCAwLCAwLCAwKSwgdW5pdCA9ICJsaW5lcyIpCiAgKQopCgpwbG90X3JlcHJlc2VudGF0aW9uIDwtIGZ1bmN0aW9uKHJlcF9kZiwgcmVsYXRpb25fdmFsdWUsIG5fYnJlYWtzID0gMykgewogIHBsb3RfZGYgPC0gcmVwX2RmICU+JQogICAgZmlsdGVyKGZyb20gIT0gdG8pICU+JQogICAgZ3JvdXBfYnkoZnJvbSwgdG8pICU+JQogICAgc3VtbWFyaXNlKHZhbHVlID0gbWVhbih7e3JlbGF0aW9uX3ZhbHVlfX0pLCAuZ3JvdXBzID0gImRyb3AiKQogIAogIHBsb3RfZGYgJT4lCiAgICAjIFBsb3QKICAgIG11dGF0ZSgKICAgICAgYWNyb3NzKGMoZnJvbSwgdG8pLCBmYWN0b3IpLAogICAgICBmcm9tID0gZmN0X3Jldihmcm9tKQogICAgKSAlPiUKICAgIGdncGxvdChhZXMoeD10bywgeT1mcm9tLCBmaWxsPXZhbHVlKSkgKwogICAgZ2cgKwogICAgZ2VvbV90aWxlKCkgKwogICAgY29vcmRfZml4ZWQoKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYygKICAgICAgb3B0aW9uID0gIm1hZ21hIiwgbmFtZSA9IE5VTEwsIG5hLnZhbHVlID0gIndoaXRlIiwgbi5icmVha3MgPSBuX2JyZWFrcwogICAgKSArCiAgICB0aGVtZSgKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpCiAgICApCn0KCmNoZWNrX3NpZ25pZmljYW5jZSA8LSBmdW5jdGlvbih0aWR5X3N0YXRzKSB7CiAgdGlkeV9zdGF0cyAlPiUKICAgIG11dGF0ZSgKICAgICAgc2lnbmlmaWNhbmNlID0gY2FzZV93aGVuKAogICAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICAgIHAudmFsdWUgPCAwLjAxIH4gIioqIiwKICAgICAgICBwLnZhbHVlIDwgMC4wNSB+ICIqIiwKICAgICAgICBwLnZhbHVlIDwgMC4xIH4gIi4iLAogICAgICAgIFRSVUUgfiAiIgogICAgICApCiAgICApCn0KYGBgCgpUaGVzZSBkYXRhIGFyZSBpbmNsdWRlZCBpbiBLcmFja2hhcmR0IDE5ODcsIEFwcGVuZGl4IEEuIEVhY2ggYWxsb2NlbnRyaWMgQ1NWIGNvbnRhaW5zIGFuIGFkamFjZW5jeSBtYXRyaXgsIHNvIHdlJ2xsIG5lZWQgdG8gZG8gYSBsaXR0bGUgd29yayB0byBnZXQgdGhlbSBpbnRvIGEgdGlkeS1mcmllbmRseSBmb3JtYXQuCgpUaGUgImVnb2NlbnRyaWMiIG5ldHdvcmsgaXMgZGVmaW5lZCBpbiB0aGUgd2F5IHRoYXQgc29jaWFsIG5ldHdvcmtzIGFyZSBtb3N0IG9mdGVuIGRlZmluZWQ6IGJhc2VkIG9uIGVhY2ggc3ViamVjdCdzIGFuc3dlciB0byB0aGUgcXVlc3Rpb24sICJXaG8gYXJlIHlvdSBjb25uZWN0ZWQgdG8/IiBPZnRlbnRpbWVzLCB0aGlzIHF1ZXN0aW9uIGlzIHBocmFzZWQgdG8gbWVhc3VyZSBmcmllbmRzaGlwcyAoZS5nLiwgIkFyZSB5b3UgZnJpZW5kcyB3aXRoIFg/IikuIEluIHRoaXMgcGFydGljdWxhciBkYXRhc2V0LCB0aGUgcXVlc3Rpb24gaXMgc29tZXRoaW5nIGNsb3NlciB0byAiV2hvIGRvIHlvdSBhc2sgZm9yIGFkdmljZT8iCgpUaGUgImFsbG9jZW50cmljIiBjb2duaXRpdmUgbWFwcyBtZWFzdXJlIGVhY2ggc3ViamVjdCdzIGFuc3dlciB0byB0aGUgcXVlc3Rpb24sICJEb2VzIFggYXNrIFkgZm9yIGFkdmljZT8iIFRoaXMgaW5jbHVkZXMgdGhlIHNwZWNpYWwgY2FzZSBvZiwgIkRvZXMgWCBhc2sgeW91IGZvciBhZHZpY2U/IiBIZXJlJ3MgdGhlIHJhdGlvbmFsZSBmb3IgaW5jbHVkaW5nIHRoZSBzcGVjaWFsIGNhc2UgaW4gYWxsb2NlbnRyaWMgbWFwcy4gSW1hZ2luZSBmb3IgYSBtb21lbnQgdGhhdCB0aGlzIHdlcmUgYSBzdHVkeSBhYm91dCBmcmllbmRzaGlwcyBpbnN0ZWFkIG9mIGFkdmljZS1naXZpbmcuIEluIHRoYXQgY2FzZSwgd2Ugd291bGQgY29uc2lkZXIgIkFyZSB5b3UgZnJpZW5kcyB3aXRoIFg/IiB0byBiZSBhIHF1ZXN0aW9uIHRoYXQgc3ViamVjdHMgd291bGQga25vdyB0aGUgYW5zd2VyIHRvIChvciBhdCBsZWFzdCwgdGhleSB3b3VsZCBrbm93IGJldHRlciB0aGFuIGFueW9uZSBlbHNlKS4gT24gdGhlIG90aGVyIGhhbmQsIHdlIHdvdWxkIGNvbnNpZGVyIHRoZSBxdWVzdGlvbiAiRG9lcyBYIGNvbnNpZGVyIHlvdSBhIGZyaWVuZD8iIHRvIGJlIG1vcmUgb2YgYW4gaW5mZXJlbmNlIHRoYW4ga25vd2xlZGdlLiBJIGRvbid0IGtub3cgd2hldGhlciBYIGNvbnNpZGVycyBtZSBhIGZyaWVuZDsgSSBkb24ndCBjb25zaWRlciBYIHRvIGJlIGEgZnJpZW5kLCBidXQgd2UgZG8gb2NjYXNpb25hbGx5IGVhdCBsdW5jaCB0b2dldGhlci4gTW9yZW92ZXIsIGluIGNhc2VzIG9mIGRpc2FncmVlbWVudCAoWCBzYXlzIGhlIGFza3MgWSBmb3IgYWR2aWNlOyBZIGRvZXNuJ3QgYWdyZWUpLCB0aGUgImdyb3VuZCB0cnV0aCIgZWdvY2VudHJpYyBuZXR3b3JrIHdvdWxkIHRoZW4gaGluZ2Ugb24gdGhlIHJlc2VhcmNoZXIncyBkZWNpc2lvbiB0byB1c2UgYW4gaW50ZXJzZWN0aW9uIHZzIHVuaW9uIHJ1bGUgdG8gcmVzb2x2ZSBkaXNhZ3JlZW1lbnRzOyBLcmFja2hhcmR0IG5vdGVzIHRoaXMgaW4gaGlzIHBhcGVyLiBCeSBhbHRlcm5hdGl2ZWx5IGRlZmluaW5nIHRoZSBlZ29jZW50cmljIG5ldHdvcmsgYmFzZWQgc29sZWx5IG9uIHRoZSByZXNwb25zZXMgdGhhdCBzdWJqZWN0cyB3b3VsZCBoYXZlIGdyZWF0ZXN0IGludHJvc3BlY3RpdmUgYWNjZXNzIHRvICh0aGVpciBvd24gYWR2aWNlLXNlZWtpbmcgYmVoYXZpb3IpLCB3ZSBzaWRlc3RlcCB0aGlzIHJlc2VhcmNoZXIgZGVncmVlIG9mIGZyZWVkb20uCgpgYGB7ciBjbGVhbi1kYXRhfQprcmFja2hhcmR0X3JhdyA8LSBoZXJlKCJkYXRhIiwgImtyYWNraGFyZHQiKSAlPiUKICBmczo6ZGlyX2xzKHJlZ2V4cCA9ICJrcmFja2hhcmR0X3RlY2hfbWFuYWdlcnNfc3ViW1s6ZGlnaXQ6XV17Mn1cXC5jc3YiKSAlPiUKICBtYXBfZGZyKAogICAgLmYgPSB+cmVhZF9jc3YoLngsIGNvbF9uYW1lcyA9IEZBTFNFLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSwKICAgIC5pZCA9ICJmaWxlbmFtZSIKICApICU+JQogIG11dGF0ZSgKICAgIHN1Yl9pZCA9IHN0cl9leHRyYWN0KGZpbGVuYW1lLCAic3ViW1s6ZGlnaXQ6XV17Mn0iKSwKICAgIHN1Yl9pZCA9IHN0cl9yZW1vdmUoc3ViX2lkLCAic3ViIiksCiAgICBzdWJfaWQgPSBhcy5udW1lcmljKHN1Yl9pZCkKICApICU+JQogIHNlbGVjdCgtZmlsZW5hbWUpICU+JQogIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgbXV0YXRlKGZyb20gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gLWMoc3ViX2lkLCBmcm9tKSwKICAgIG5hbWVzX3RvID0gInRvIiwKICAgIHZhbHVlc190byA9ICJlZGdlIgogICkgJT4lCiAgbXV0YXRlKAogICAgdG8gPSBzdHJfcmVtb3ZlKHRvLCAiWCIpLAogICAgdG8gPSBhcy5pbnRlZ2VyKHRvKQogICkKCmtyYWNraGFyZHRfZWdvY2VudHJpYyA8LSBrcmFja2hhcmR0X3JhdyAlPiUKICBmaWx0ZXIoc3ViX2lkID09IGZyb20sIGZyb20gIT0gdG8pICU+JQogIHNlbGVjdCgtc3ViX2lkKQoKa3JhY2toYXJkdF9hbGxvY2VudHJpYyA8LSBrcmFja2hhcmR0X3JhdyAlPiUKICBmaWx0ZXIoc3ViX2lkICE9IGZyb20sIGZyb20gIT0gdG8pCmBgYAoKCiMgUGxvdCBkYXRhCgpPa2F5LCBsZXQncyB0cnkgYW5kIGdldCBhIHNlbnNlIGZvciB3aGF0IHRoZSAiZWdvY2VudHJpYyIgbmV0d29yayBsb29rcyBsaWtlLgoKYGBge3IgbmV0d29yay1ncmFwaH0Ka3JhY2toYXJkdF9nIDwtIGtyYWNraGFyZHRfZWdvY2VudHJpYyAlPiUKICBmaWx0ZXIoZWRnZSA9PSAxKSAlPiUKICBzZWxlY3QoLWVkZ2UpICU+JSAKICB0YmxfZ3JhcGgoZWRnZXMgPSAuKSAlPiUKICBtdXRhdGUobmFtZSA9IHJvd19udW1iZXIoKSkKCnBsb3RfbmV0d29ya19ncmFwaCA8LSBrcmFja2hhcmR0X2cgJT4lCiAgbXV0YXRlKERlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKG1vZGUgPSAiaW4iKSkgJT4lCiAgIyBQbG90IHRoZSAiZ3JvdW5kIHRydXRoIiBuZXR3b3JrCiAgZ2dyYXBoKGxheW91dCA9ICJzdHJlc3MiKSArCiAgZ2VvbV9lZGdlX2xpbmsoCiAgICBhZXMoCiAgICAgIHN0YXJ0X2NhcCA9IGxhYmVsX3JlY3Qobm9kZTEubmFtZSwgcGFkZGluZyA9IG1hcmdpbigxNSwgMTUsIDE1LCAxNSkpLAogICAgICBlbmRfY2FwID0gbGFiZWxfcmVjdChub2RlMi5uYW1lLCBwYWRkaW5nID0gbWFyZ2luKDE1LCAxNSwgMTUsIDE1KSksCiAgICApLAogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDUsICJwdCIpLCB0eXBlID0gImNsb3NlZCIpCiAgKSArCiAgZ2VvbV9ub2RlX2xhYmVsKAogICAgYWVzKGxhYmVsID0gbmFtZSwgc2l6ZSA9IERlZ3JlZSksCiAgICBmaWxsID0gImdyZXk5NSIsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygzLCAxMCkpICsKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTMpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEzKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKcGxvdF9uZXR3b3JrX2dyYXBoCmBgYAoKV2UgY2FuIGFsc28gcGxvdCB0aGlzIGFzIGEgbWF0cml4IGluc3RlYWQgb2YgYSBncmFwaCwgd2hpY2ggd2lsbCBlYXNlIGNvbXBhcmlzb24gd2l0aCB0aGUgY29nbml0aXZlIHN0cmF0ZWdpZXMgd2UnbGwgY29uc2lkZXIgbmV4dC4KCmBgYHtyIG5ldHdvcmstYWRqYWNlbmN5fQpwbG90X25ldHdvcmtfYWRqIDwtIGtyYWNraGFyZHRfZWdvY2VudHJpYyAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKGVkZ2UsIG5fYnJlYWtzID0gMikgKwogIGdndGl0bGUoIkVnb2NlbnRyaWMgTmV0d29yayIpCgpwbG90X25ldHdvcmtfYWRqCmBgYAoKSG93IGRvZXMgdGhpcyBjb21wYXJlIHRvIHN1YmplY3RzJyBtZW50YWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIG5ldHdvcms/CgpgYGB7ciBwbG90LXJlcHJlc2VudGF0aW9ufQpwbG90X2Nob2ljZSA8LSBrcmFja2hhcmR0X2FsbG9jZW50cmljICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBlZGdlKSArCiAgZ2d0aXRsZSgiTmV0d29yayBSZXByZXNlbnRhdGlvbiIpCgpwbG90X25ldHdvcmtfYWRqIHwgcGxvdF9jaG9pY2UKYGBgCgpJbiB0aGUgb3JpZ2luYWwgcGFwZXIsIEtyYWNraGFyZHQgbWFrZXMgdGhlIGZvbGxvd2luZyBub3RlOiAiVGhlcmUgYXJlIHNvbWUgY2VudGVycyBvZiBmb2N1cyBmb3IgYWR2aWNlLCBub3RhYmx5IDIgYW5kIDIxIChib3RoIGFyZSB2aWNlIHByZXNpZGVudHMpIC4uLiBJbiBbdGhlIHN1YmplY3RpdmVseSBwZXJjZWl2ZWQgbmV0d29ya10sIDIxIGxvc2VzIGhpcyBwcm9taW5lbmNlIGFzIGEgbWFqb3IgcmVjaXBpZW50IG9mIG5vbWluYXRpb25zOiBpbnN0ZWFkLCAxOCwgMTQsIGFuZCA3ICh0aGUgcHJlc2lkZW50KSBhcHBlYXIgdG8gYmUgbW9yZSBjZW50cmFsLiIgVG8gZ2V0IGEgcXVhbnRpdGF0aXZlIHNlbnNlIGZvciB0aGlzIGluIG91ciBkYXRhLCB3ZSBjYW4gdHJ5IGNhbGN1bGF0aW5nIHRoZSAicGVyY2VpdmVkIiBkZWdyZWUgY2VudHJhbGl0eSBieSBzdW1taW5nIG92ZXIgdGhlIG1hdHJpeCBjb2x1bW5zLCB0aGVuIGNvbXBhcmluZyB0aGF0IGFnYWluc3QgdGhlICJ0cnVlIiBpbi1kZWdyZWUgY2VudHJhbGl0eS4KCmBgYHtyIGNhbGMtY2VudHJhbGl0eS1kaWZmfQpjZW50cmFsaXR5X2RpZmZlcmVuY2VzIDwtIGtyYWNraGFyZHRfZyAlPiUKICBtdXRhdGUoCiAgICBEZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIiksCiAgICBCZXR3ZWVubmVzcyA9IGNlbnRyYWxpdHlfYmV0d2Vlbm5lc3MoZGlyZWN0ZWQgPSBUUlVFKQogICkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgIyBBZGQgcmVwcmVzZW50ZWQgaW4tZGVncmVlOyBzdGFuZGFyZGl6ZSBzdW0gYnkgbnVtYmVyIG9mIG5ldHdvcmsgbWVtYmVycwogIGxlZnRfam9pbigKICAgIGtyYWNraGFyZHRfYWxsb2NlbnRyaWMgJT4lCiAgICAgIGdyb3VwX2J5KG5hbWUgPSB0bykgJT4lCiAgICAgIHN1bW1hcmlzZShQZXJjZWl2ZWQgPSBzdW0oZWRnZSkvMjEsIC5ncm91cHMgPSAiZHJvcCIpLAogICAgYnkgPSBjKCJuYW1lIikKICApICU+JQogIHNlbGVjdChuYW1lLCBQZXJjZWl2ZWQsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgYXJyYW5nZShkZXNjKERlZ3JlZSksIGRlc2MoUGVyY2VpdmVkKSkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlIHNhbWUgbnVtYmVyIG9mIG1hbmFnZXJzIGdvIHRvIHN1YmplY3RzIDE4IGFuZCAyMSBmb3IgYWR2aWNlICgxNSBlYWNoKSwgYnV0IHRoYXQgc3ViamVjdCAxOCBpcyBwZXJjZWl2ZWQgYXMgYmVpbmcgbXVjaCBtb3JlICJwb3B1bGFyIiAoYXZlcmFnZWQgYWNyb3NzIHN1YmplY3RzLCAxMS45NSBtYW5hZ2VycyBhcmUgcGVyY2VpdmVkIHRvIGdvIHRvIGhpbSBmb3IgYWR2aWNlKSB0aGFuIHN1YmplY3QgMjEgKGF2ZXJhZ2VkIGFjcm9zcyBzdWJqZWN0cywgOC4zOCBtYW5hZ2VycyBhcmUgcGVyY2VpdmVkIHRvIGdvIHRvIGhpbSBmb3IgYWR2aWNlKS4gQSBzaW1pbGFyIHBoZW5vbWVub24gaGFwcGVucyB3aXRoIHN1YmplY3RzIDEgYW5kIDcsIHdoZXJlIHN1YmplY3QgMSBpcyBwZXJjZWl2ZWQgYXMgYmVpbmcgbXVjaCBsZXNzIHBvcHVsYXIgdGhhbiBzdWJqZWN0IDcsIGRlc3BpdGUgdGhlaXIgaGF2aW5nIHRoZSBzYW1lICJ0cnVlIiBwb3B1bGFyaXR5LgoKYGBge3IgY2VudHJhbGl0eS1kaWZmLWRlZ3JlZX0KY2VudHJhbGl0eV9kaWZmZXJlbmNlcyAlPiUKICBnZ3Bsb3QoYWVzKHg9RGVncmVlLCB5PVBlcmNlaXZlZCkpICsKICBnZyArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKwogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gbmFtZSkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJUcnVlIChkZWdyZWUpIGNlbnRyYWxpdHkiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiUGVyY2VpdmVkIGNlbnRyYWxpdHkiKQoKY2VudHJhbGl0eV9kaWZmZXJlbmNlcyAlPiUKICBzZWxlY3QobmFtZSwgRGVncmVlLCBQZXJjZWl2ZWQpICU+JQogIGthYmxlKCkKYGBgCgpJcyBpdCBwb3NzaWJsZSB0aGF0IHN1YmplY3RzJyBuZXR3b3JrIHJlcHJlc2VudGF0aW9ucyBtaWdodCBiZSByZWZsZWN0aW5nIHNvbWUgb3RoZXIgY2VudHJhbGl0eSBtZXRyaWM/IEluIHRoZSBvcmlnaW5hbCBwYXBlciwgS3JhY2toYXJkdCBub3RlcyB0aGF0IGJldHdlZW5uZXNzIHNlZW1zIHRvIGhhdmUgc29tZSBwcmVkaWN0aXZlIHBvd2VyLiBGb3IgdGhlIDE4LTIxIGFuZCAxLTcgdGVzdCBjYXNlcywgd2Ugc2VlIHRoYXQgYmV0d2Vlbm5lc3MgY2VudHJhbGl0eSBkb2VzIG1ha2UgdGhlICJjb3JyZWN0IiBwcmVkaWN0aW9uIGFib3V0IHdoaWNoIG5ldHdvcmsgbWVtYmVyIGlzIHJlcHJlc2VudGVkIGFzIGJlaW5nIG1vcmUgaW1wb3J0YW50LiBCdXQsIHdlIHNob3VsZCBub3RlIHRoYXQgYmV0d2Vlbm5lc3MgZG9lc24ndCBkbyB0aGUgZ3JlYXRlc3Qgam9iIHByZWRpY3RpbmcgcGVyY2VpdmVkIHBvcHVsYXJpdHkgYWNyb3NzIHRoZSBib2FyZDsgaXRzIGdyZWF0ZXN0IHByZWRpY3RpdmUgcG93ZXIgaXMgaW4gZXhwbGFpbmluZyB0aGUgcG9wdWxhcml0eSBkaXNjcmVwYW5jeSBmb3IgdGhlIG1vc3QgcG9wdWxhciBtYW5hZ2Vycy4KCmBgYHtyIGNlbnRyYWxpdHktZGlmZmVyZW5jZXMtYmV0d2Vlbn0KY2VudHJhbGl0eV9kaWZmZXJlbmNlcyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IERlZ3JlZTpCZXR3ZWVubmVzcywgbmFtZXNfdG8gPSAibWV0cmljIikgJT4lCiAgZ2dwbG90KGFlcyh4PXZhbHVlLCB5PVBlcmNlaXZlZCkpICsKICBnZyArCiAgZmFjZXRfd3JhcCh+bWV0cmljLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICBnZW9tX2xhYmVsKGFlcyhsYWJlbCA9IG5hbWUpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiVHJ1ZSBjZW50cmFsaXR5IikgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlaXZlZCBjZW50cmFsaXR5IikKCmNlbnRyYWxpdHlfZGlmZmVyZW5jZXMgJT4lCiAga2FibGUoKQpgYGAKCgojIFNpbXVsYXRlZCBvYnNlcnZhdGlvbnMKCldlIGtub3cgdGhhdCBhbiBpbmRpdmlkdWFsJ3MgZW1iZWRkaW5nIHdpdGhpbiBhIG5ldHdvcmsgZGljdGF0ZXMgd2hhdCBpbnRlcmFjdGlvbnMgYW5kL29yIHJlbGF0aW9uc2hpcHMgdGhleSdyZSBhYmxlIHRvIG9ic2VydmUuIFRoZXJlZm9yZSwgd2hlbiBidWlsZGluZyBwcmVkaWN0ZWQgY29nbml0aXZlIG1hcHMsIHdlIHNob3VsZCB1c2UgYSBkaWZmZXJlbnQgc2V0IG9mIGludGVyYWN0aW9ucyB0byBpbmZvcm0gZWFjaCBzdWJqZWN0J3MgcHJlZGljdGVkIHJlcHJlc2VudGF0aW9ucy4gT2YgY291cnNlLCB3ZSBoYXZlIG5vIGlkZWEgd2hhdCBpbmRpdmlkdWFsIHN1YmplY3RzJyBvYnNlcnZhdGlvbnMgYWN0dWFsbHkgYXJlLiBTbyB3ZSdsbCBuZWVkIHRvIGNvbWUgdXAgd2l0aCBhIGNvbXBhY3QgYW5kIHJlYXNvbmFibGUgc2V0IG9mIGFzc3VtcHRpb25zIGFib3V0IHdoYXQgb2JzZXJ2YXRpb25zIHdlcmUgbW9zdCBsaWtlbHkgYXZhaWxhYmxlIHRvIGluZGl2aWR1YWwgbmV0d29yayBtZW1iZXJzLgoKSGVyZSBhcmUgdGhyZWUga2V5IGFzc3VtcHRpb25zIHdlJ2xsIG1ha2UgaGVyZToKCjEuIFdlJ2xsIGFzc3VtZSAodHJpdmlhbGx5KSB0aGF0IHBlb3BsZSBjYW4gb2JzZXJ2ZSBpbnRlcmFjdGlvbnMgYmV0d2VlbiB0aGVtc2VsdmVzIGFuZCB0aGVpciBpbW1lZGlhdGUgYWR2aXNvcnMgKGFuZC9vciBhZHZpc2VlcykuCjIuIFdlJ2xsIGFsc28gYXNzdW1lIHRoYXQgcGVvcGxlIGFyZSBnZW5lcmFsbHkgYWJsZSB0byBvYnNlcnZlIGludGVyYWN0aW9ucyBiZXR3ZWVuIGFkdmlzb3JzLW9mLWFkdmlzb3JzIChhbmQvb3IgYWR2aXNlZXMtb2YtYWR2aXNlZXMpLCBlaXRoZXIgdGhyb3VnaCBmaXJzdGhhbmQgb2JzZXJ2YXRpb24gb3Igc2Vjb25kaGFuZCBjaGF0dGVyLgozLiBUaG91Z2ggb2YgY291cnNlIGl0J3MgcGxhdXNpYmxlIHRoYXQgcGVvcGxlIG1pZ2h0IG9ic2VydmUgbW9yZSBkaXN0YW50IGludGVyYWN0aW9ucywgd2UnbGwgYXNzdW1lIHRoaXMgaGFwcGVucyB3aXRoIGVub3VnaCBpbmZyZXF1ZW5jeSB0aGF0IHdlIGNhbiBpZ25vcmUgdGhvc2UgaW50ZXJhY3Rpb25zIGZvciB0aGUgc2FrZSBvZiBtb2RlbGluZy4KCldlJ3ZlIGxlZnQgb3BlbiBhbiBhbWJpZ3VpdHkgaW4gdGhvc2UgYXNzdW1wdGlvbnM6IGFyZSBwZW9wbGUgb2JzZXJ2aW5nIGFkdmlzb3JzLW9mLWFkdmlzb3JzLCBhbmQvb3IgYWR2aXNlZXMtb2YtYWR2aXNlZXM/IFRvIGFpZCB1bmRlcnN0YW5kaW5nLCB3ZSdsbCB1c2UgdGhlIGZvbGxvd2luZyBleGFtcGxlLiBTdXBwb3NlIHdlJ3JlIGxvb2tpbmcgYXQgYSBzdWJzZXQgb2YgYSBuZXR3b3JrIGNvbnNpc3Rpbmcgb2YgdGhlIGdyYWQgc3R1ZGVudCBBYmJ5LCB3aG8gYXNrcyB0aGUgcG9zdGRvYyBCZXR0eSBmb3IgYWR2aWNlOyBpbiB0dXJuLCBCZXR0eSB0aGUgcG9zdGRvYyBhc2tzIENhdGh5IHRoZSBhc3Npc3RhbnQgcHJvZmVzc29yIGZvciBhZHZpY2U7IGFuZCBDYXRoeSBhc2tzIERhbmkgdGhlIGFzc29jaWF0ZSBwcm9mZXNzb3IgZm9yIGFkdmljZS4gVGhlcmUgYXJlIHRocmVlIHJlYXNvbmFibGUgd2F5cyB0aGF0IG9ic2VydmF0aW9ucyBtaWdodCB3b3JrIGluIHRoaXMgbmV0d29yazoKCjEuIE9ic2VydmF0aW9ucyBnbyAib3V0IjogV2hlbiBBYmJ5IGFza3MgQmV0dHkgZm9yIGFkdmljZSwgQmV0dHkgcmVzcG9uZHMgYnkgc2hhcmluZyB0aGUgd2lzZG9tIHNoZSdzIGdhaW5lZCBmcm9tIGFza2luZyBDYXRoeSBmb3IgYWR2aWNlLiBUaGF0IGxlYWRzIEFiYnkgdG8gb2JzZXJ2ZSB0aGF0IEJldHR5IGdvZXMgdG8gQ2F0aHkgZm9yIGFkdmljZS4KMi4gT2JzZXJ2YXRpb25zIGdvICJpbiI6IEJldHR5IGhhcyBhc2tlZCBDYXRoeSBmb3IgYWR2aWNlLiBDYXRoeSB0aGlua3MgQmV0dHkgaGFzIGFza2VkIGEgZ3JlYXQgcXVlc3Rpb24gdGhhdCBzaGUgZG9lc24ndCBrbm93IHRoZSBhbnN3ZXIgdG8sIHNvIENhdGh5IGFza3MgRGFuaSBhYm91dCBpdC4gVGhhdCBsZWFkcyBEYW5pIHRvIG9ic2VydmUgdGhhdCBCZXR0eSBnb2VzIHRvIENhdGh5IGZvciBhZHZpY2UuCjMuIEl0IGdvZXMgYm90aCB3YXlzLgoKV2UgbWF5IGJlIGFibGUgdG8gdGVzdCB0aGlzIGVtcGlyaWNhbGx5LiBXZSB3b3VsZCBuZWVkIHRvIHNpbXVsYXRlIGEgc2V0IG9mIG9ic2VydmF0aW9ucyBjb25zaXN0ZW50IHdpdGggYWxsIHRocmVlIHBvc3NpYmlsaXRpZXMsIGdlbmVyYXRlIG1vZGVsIHByZWRpY3Rpb25zIGZyb20gdGhvc2Ugc2ltdWxhdGlvbnMsIHRoZW4gY29tcGFyZSBob3cgd2VsbCB0aG9zZSBtb2RlbHMgZml0IG1hbmFnZXJzJyBhY3R1YWwgcGVyY2VwdGlvbnMgb2YgdGhlIG5ldHdvcmsuCgpgYGB7ciBkZWYtb2JzZXJ2YXRpb25zfQojIE9ic2VydmF0aW9ucyBnbyBib3RoIHdheXMKb2JzX2VkZ2VsaXN0X2FsbCA8LSBleHBhbmRfZ3JpZCgKICBzdWJfaWQgPSAxOjIxLAogICMgU3RhcnQgd2l0aCBhbGwgb25lLXN0ZXAgZWdvY2VudHJpYyBvYnNlcnZhdGlvbnMKICBrcmFja2hhcmR0X2Vnb2NlbnRyaWMKKSAlPiUKICAjIENvbnZlcnQgYWRqbGlzdCBpbnRvIGVkZ2VsaXN0CiAgZmlsdGVyKGVkZ2UgPT0gMSkgJT4lCiAgc2VsZWN0KC1lZGdlKSAlPiUKICAjIEZvciBhIGdpdmVuIG5vZGUsIHdlIHdhbnQgdG8ga25vdyB3aG8gdGhlaXIgImFkdmlzb3JzLW9mLWFkdmlzb3JzIiBhcmUKICAjIChvciBlcXVpdmFsZW50bHksICJhZHZpc2Vlcy1vZi1hZHZpc2VlcyIpCiAgbGVmdF9qb2luKAogICAga3JhY2toYXJkdF9nICU+JQogICAgICBtdXRhdGUobmVpZ2hib3JzID0gbG9jYWxfbWVtYmVycyhvcmRlciA9IDEsIG1vZGUgPSAiYWxsIikpICU+JQogICAgICBhc190aWJibGUoKSwKICAgIGJ5ID0gYygic3ViX2lkIiA9ICJuYW1lIikKICApICU+JQogICMgV2UgYXNzdW1lIHRoYXQgbm9kZXMgYXJlIGFibGUgdG8gb2JzZXJ2ZSAoZGlyZWN0bHkgb3IgdGhyb3VnaCBjaGF0dGVyKQogICMgYWR2aWNlLWdpdmluZyBpbnRlcmFjdGlvbnMgZnJvbSB0aGVpciBhZHZpc29ycyBhbmQgYWR2aXNvcnMtb2YtYWR2aXNvcnMKICAjIChvciBlcXVpdmFsZW50bHksIGFkdmlzZWVzIGFuZCBhZHZpc2Vlcy1vZi1hZHZpc2VlcykKICByb3d3aXNlKCkgJT4lCiAgZmlsdGVyKChmcm9tICVpbiUgbmVpZ2hib3JzKSB8ICh0byAlaW4lIG5laWdoYm9ycykpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLW5laWdoYm9ycykgJT4lCiAgIyBNYWtlIHByZXR0eQogIGFycmFuZ2Uoc3ViX2lkLCBmcm9tKQoKIyBBZHZpc2VlcyBvYnNlcnZlIHdobyBhZHZpc2VzIHRoZWlyIGFkdmlzb3JzCm9ic19lZGdlbGlzdF9vdXQgPC0gZXhwYW5kX2dyaWQoCiAgc3ViX2lkID0gMToyMSwKICBrcmFja2hhcmR0X2Vnb2NlbnRyaWMKKSAlPiUKICBmaWx0ZXIoZWRnZSA9PSAxKSAlPiUKICBzZWxlY3QoLWVkZ2UpICU+JQogIGxlZnRfam9pbigKICAgIGtyYWNraGFyZHRfZyAlPiUKICAgICAgbXV0YXRlKG5laWdoYm9ycyA9IGxvY2FsX21lbWJlcnMob3JkZXIgPSAxLCBtb2RlID0gIm91dCIpKSAlPiUKICAgICAgYXNfdGliYmxlKCksCiAgICBieSA9IGMoInN1Yl9pZCIgPSAibmFtZSIpCiAgKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgZmlsdGVyKChmcm9tICVpbiUgbmVpZ2hib3JzKSB8ICh0byAlaW4lIG5laWdoYm9ycykpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLW5laWdoYm9ycykgJT4lCiAgYXJyYW5nZShzdWJfaWQsIGZyb20pCgojIEFkdmlzb3JzIG9ic2VydmUgd2hvIHRoZWlyIGFkdmlzZWVzIGFkdmlzZQpvYnNfZWRnZWxpc3RfaW4gPC0gZXhwYW5kX2dyaWQoCiAgc3ViX2lkID0gMToyMSwKICBrcmFja2hhcmR0X2Vnb2NlbnRyaWMKKSAlPiUKICBmaWx0ZXIoZWRnZSA9PSAxKSAlPiUKICBzZWxlY3QoLWVkZ2UpICU+JQogIGxlZnRfam9pbigKICAgIGtyYWNraGFyZHRfZyAlPiUKICAgICAgbXV0YXRlKG5laWdoYm9ycyA9IGxvY2FsX21lbWJlcnMob3JkZXIgPSAxLCBtb2RlID0gImluIikpICU+JQogICAgICBhc190aWJibGUoKSwKICAgIGJ5ID0gYygic3ViX2lkIiA9ICJuYW1lIikKICApICU+JQogIHJvd3dpc2UoKSAlPiUKICBmaWx0ZXIoKGZyb20gJWluJSBuZWlnaGJvcnMpIHwgKHRvICVpbiUgbmVpZ2hib3JzKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtbmVpZ2hib3JzKSAlPiUKICBhcnJhbmdlKHN1Yl9pZCwgZnJvbSkKCm9ic19hZGpsaXN0X2FsbCA8LSBleHBhbmRfZ3JpZChzdWJfaWQgPSAxOjIxLCBmcm9tID0gc3ViX2lkLCB0byA9IHN1Yl9pZCkgJT4lCiAgbGVmdF9qb2luKAogICAgb2JzX2VkZ2VsaXN0X2FsbCAlPiUgbXV0YXRlKGVkZ2UgPSAxKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkgJT4lCiAgbXV0YXRlKGVkZ2UgPSBpZl9lbHNlKGlzLm5hKGVkZ2UpLCAwLCBlZGdlKSkKCm9ic19hZGpsaXN0X291dCA8LSBleHBhbmRfZ3JpZChzdWJfaWQgPSAxOjIxLCBmcm9tID0gc3ViX2lkLCB0byA9IHN1Yl9pZCkgJT4lCiAgbGVmdF9qb2luKAogICAgb2JzX2VkZ2VsaXN0X291dCAlPiUgbXV0YXRlKGVkZ2UgPSAxKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkgJT4lCiAgbXV0YXRlKGVkZ2UgPSBpZl9lbHNlKGlzLm5hKGVkZ2UpLCAwLCBlZGdlKSkKCm9ic19hZGpsaXN0X2luIDwtIGV4cGFuZF9ncmlkKHN1Yl9pZCA9IDE6MjEsIGZyb20gPSBzdWJfaWQsIHRvID0gc3ViX2lkKSAlPiUKICBsZWZ0X2pvaW4oCiAgICBvYnNfZWRnZWxpc3RfaW4gJT4lIG11dGF0ZShlZGdlID0gMSksCiAgICBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikKICApICU+JQogIG11dGF0ZShlZGdlID0gaWZfZWxzZShpcy5uYShlZGdlKSwgMCwgZWRnZSkpCmBgYAoKCiMgU2NoZW1hLWJhc2VkIHJlcHJlc2VudGF0aW9uCgpJZiBwZW9wbGUgd2VyZSB1c2luZyB0cmlhZCBvciBjb21tdW5pdHkgc2NoZW1hcy9oZXVyaXN0aWNzIHRvIGluZm9ybSByZXByZXNlbnRhdGlvbiwgd2hhdCB3b3VsZCB0aGlzIGxvb2sgbGlrZT8gVXNpbmcgbGl0ZXJhbGx5IHRoZSBleGFjdCBzYW1lIHRvb2xzIHRoYXQgd2UgdXNlZCB0byBhbmFseXplIHRoZSBidXR0ZXJmbHkgbmV0d29yaywgbGV0J3MgY3JlYXRlIHNvbWUgcHJlZGljdGVkIHJlcHJlc2VudGF0aW9ucy4KCmBgYHtyIHNjaGVtYS1leHBlcnRzfQpzY2hlbWFfZXhwZXJ0c19hbGwgPC0gb2JzX2Fkamxpc3RfYWxsICU+JQogICMgTWVtb3JpemF0aW9uCiAgZ3JvdXBfYnkoc3ViX2lkLCBmcm9tKSAlPiUKICBtdXRhdGUoCiAgICBtZW1fdmFsdWUgPSBlZGdlIC8gc3VtKGVkZ2UpLAogICAgbWVtX3ZhbHVlID0gaWZfZWxzZShpcy5uYW4obWVtX3ZhbHVlKSwgMCwgbWVtX3ZhbHVlKQogICkgJT4lCiAgdW5ncm91cCgpICU+JQogICMgTm93IHRyaWFkcwogIGxlZnRfam9pbigKICAgIG9ic19hZGpsaXN0X2FsbCAlPiUKICAgICAgZ3JvdXBfYnkoc3ViX2lkKSAlPiUKICAgICAgbmVzdCgpICU+JQogICAgICBtdXRhdGUodHJpYWQgPSBtYXAoZGF0YSwgfmJ1aWxkX3JlcF90cmlhZCgueCwgImVkZ2UiKSkpICU+JQogICAgICB1bm5lc3QodHJpYWQpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCgtYyhkYXRhLCB0cmFuc2l0aW9uX3NjYWxpbmcpKSAlPiUKICAgICAgbXV0YXRlKHRyaWFkX3ZhbHVlID0gaWZfZWxzZShpcy5uYW4odHJpYWRfdmFsdWUpLCAwLCB0cmlhZF92YWx1ZSkpLAogICAgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpCiAgKSAlPiUKICAjIEZpbmFsbHkgY29tbXVuaXRpZXMKICBsZWZ0X2pvaW4oCiAgICBvYnNfYWRqbGlzdF9hbGwgJT4lCiAgICAgIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgICAgIG5lc3QoKSAlPiUKICAgICAgbXV0YXRlKGNvbW0gPSBtYXAoZGF0YSwgfmJ1aWxkX3JlcF9jb21tdW5pdHkoLngsICJlZGdlIikpKSAlPiUKICAgICAgdW5uZXN0KGNvbW0pICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCgtYyhkYXRhLCB0cmFuc2l0aW9uX3NjYWxpbmcpKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkKCnNjaGVtYV9leHBlcnRzX291dCA8LSBvYnNfYWRqbGlzdF9vdXQgJT4lCiAgIyBNZW1vcml6YXRpb24KICBncm91cF9ieShzdWJfaWQsIGZyb20pICU+JQogIG11dGF0ZSgKICAgIG1lbV92YWx1ZSA9IGVkZ2UgLyBzdW0oZWRnZSksCiAgICBtZW1fdmFsdWUgPSBpZl9lbHNlKGlzLm5hbihtZW1fdmFsdWUpLCAwLCBtZW1fdmFsdWUpCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBOb3cgdHJpYWRzCiAgbGVmdF9qb2luKAogICAgb2JzX2Fkamxpc3Rfb3V0ICU+JQogICAgICBncm91cF9ieShzdWJfaWQpICU+JQogICAgICBuZXN0KCkgJT4lCiAgICAgIG11dGF0ZSh0cmlhZCA9IG1hcChkYXRhLCB+YnVpbGRfcmVwX3RyaWFkKC54LCAiZWRnZSIpKSkgJT4lCiAgICAgIHVubmVzdCh0cmlhZCkgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KC1jKGRhdGEsIHRyYW5zaXRpb25fc2NhbGluZykpICU+JQogICAgICBtdXRhdGUodHJpYWRfdmFsdWUgPSBpZl9lbHNlKGlzLm5hbih0cmlhZF92YWx1ZSksIDAsIHRyaWFkX3ZhbHVlKSksCiAgICBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikKICApICU+JQogICMgRmluYWxseSBjb21tdW5pdGllcwogIGxlZnRfam9pbigKICAgIG9ic19hZGpsaXN0X291dCAlPiUKICAgICAgZ3JvdXBfYnkoc3ViX2lkKSAlPiUKICAgICAgbmVzdCgpICU+JQogICAgICBtdXRhdGUoY29tbSA9IG1hcChkYXRhLCB+YnVpbGRfcmVwX2NvbW11bml0eSgueCwgImVkZ2UiKSkpICU+JQogICAgICB1bm5lc3QoY29tbSkgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KC1jKGRhdGEsIHRyYW5zaXRpb25fc2NhbGluZykpLAogICAgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpCiAgKQoKc2NoZW1hX2V4cGVydHNfaW4gPC0gb2JzX2Fkamxpc3RfaW4gJT4lCiAgIyBNZW1vcml6YXRpb24KICBncm91cF9ieShzdWJfaWQsIGZyb20pICU+JQogIG11dGF0ZSgKICAgIG1lbV92YWx1ZSA9IGVkZ2UgLyBzdW0oZWRnZSksCiAgICBtZW1fdmFsdWUgPSBpZl9lbHNlKGlzLm5hbihtZW1fdmFsdWUpLCAwLCBtZW1fdmFsdWUpCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBOb3cgdHJpYWRzCiAgbGVmdF9qb2luKAogICAgb2JzX2Fkamxpc3RfaW4gJT4lCiAgICAgIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgICAgIG5lc3QoKSAlPiUKICAgICAgbXV0YXRlKHRyaWFkID0gbWFwKGRhdGEsIH5idWlsZF9yZXBfdHJpYWQoLngsICJlZGdlIikpKSAlPiUKICAgICAgdW5uZXN0KHRyaWFkKSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoLWMoZGF0YSwgdHJhbnNpdGlvbl9zY2FsaW5nKSkgJT4lCiAgICAgIG11dGF0ZSh0cmlhZF92YWx1ZSA9IGlmX2Vsc2UoaXMubmFuKHRyaWFkX3ZhbHVlKSwgMCwgdHJpYWRfdmFsdWUpKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkgJT4lCiAgIyBGaW5hbGx5IGNvbW11bml0aWVzCiAgbGVmdF9qb2luKAogICAgb2JzX2Fkamxpc3RfaW4gJT4lCiAgICAgIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgICAgIG5lc3QoKSAlPiUKICAgICAgbXV0YXRlKGNvbW0gPSBtYXAoZGF0YSwgfmJ1aWxkX3JlcF9jb21tdW5pdHkoLngsICJlZGdlIikpKSAlPiUKICAgICAgdW5uZXN0KGNvbW0pICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCgtYyhkYXRhLCB0cmFuc2l0aW9uX3NjYWxpbmcpKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkKYGBgCgpgYGB7ciBwbG90LXNjaGVtYS1hbGx9CnBsb3RfbWVtX2FsbCA8LSBwbG90X3JlcHJlc2VudGF0aW9uKHNjaGVtYV9leHBlcnRzX2FsbCwgbWVtX3ZhbHVlKSArCiAgZ2d0aXRsZSgiTWVtb3JpemF0aW9uIikKCnBsb3RfdHJpYWRfYWxsIDwtIHBsb3RfcmVwcmVzZW50YXRpb24oc2NoZW1hX2V4cGVydHNfYWxsLCB0cmlhZF92YWx1ZSkgKwogIGdndGl0bGUoIlRyaWFkIENvbXBsZXRpb24iKQoKcGxvdF9jb21tX2FsbCA8LSBwbG90X3JlcHJlc2VudGF0aW9uKHNjaGVtYV9leHBlcnRzX2FsbCwgY29tbV92YWx1ZSkgKwogIGdndGl0bGUoIkNvbW11bml0eSBEZXRlY3Rpb24iKQoKcGxvdF9zY2hlbWFzX2FsbCA8LSAoCiAgcGxvdF9jaG9pY2UgfCBwbG90X21lbV9hbGwgfCBwbG90X3RyaWFkX2FsbCB8IHBsb3RfY29tbV9hbGwKKSArCiAgcGxvdF9hbm5vdGF0aW9uKAogICAgdGl0bGUgPSAiT2JzZXJ2YXRpb25zIG9mIGFkdmljZS1naXZpbmcgZ28gYm90aCB3YXlzIiwKICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGhqdXN0ID0gMC41KSkKICApCgpwbG90X3NjaGVtYXNfYWxsCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic2NoZW1hX2dhbGxlcnlfYWxsLnBkZiIpLAogICAgcGxvdF9zY2hlbWFzX2FsbCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDQsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKYGBge3IgcGxvdC1zY2hlbWEtb3V0fQpwbG90X21lbV9vdXQgPC0gcGxvdF9yZXByZXNlbnRhdGlvbihzY2hlbWFfZXhwZXJ0c19vdXQsIG1lbV92YWx1ZSkgKwogIGdndGl0bGUoIk1lbW9yaXphdGlvbiIpCgpwbG90X3RyaWFkX291dCA8LSBwbG90X3JlcHJlc2VudGF0aW9uKHNjaGVtYV9leHBlcnRzX291dCwgdHJpYWRfdmFsdWUpICsKICBnZ3RpdGxlKCJUcmlhZCBDb21wbGV0aW9uIikKCnBsb3RfY29tbV9vdXQgPC0gcGxvdF9yZXByZXNlbnRhdGlvbihzY2hlbWFfZXhwZXJ0c19vdXQsIGNvbW1fdmFsdWUpICsKICBnZ3RpdGxlKCJDb21tdW5pdHkgRGV0ZWN0aW9uIikKCnBsb3Rfc2NoZW1hc19vdXQgPC0gKAogIHBsb3RfY2hvaWNlIHwgcGxvdF9tZW1fb3V0IHwgcGxvdF90cmlhZF9vdXQgfCBwbG90X2NvbW1fb3V0CikgKwogIHBsb3RfYW5ub3RhdGlvbigKICAgIHRpdGxlID0gIkFkdmlzZWVzIG9ic2VydmUgYWR2aXNvcnMnIGFkdmlzb3JzIiwKICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGhqdXN0ID0gMC41KSkKICApCgpwbG90X3NjaGVtYXNfb3V0CgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic2NoZW1hX2dhbGxlcnlfb3V0LnBkZiIpLAogICAgcGxvdF9zY2hlbWFzX291dCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDQsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKYGBge3IgcGxvdC1zY2hlbWEtaW59CnBsb3RfbWVtX2luIDwtIHBsb3RfcmVwcmVzZW50YXRpb24oc2NoZW1hX2V4cGVydHNfaW4sIG1lbV92YWx1ZSkgKwogIGdndGl0bGUoIk1lbW9yaXphdGlvbiIpCgpwbG90X3RyaWFkX2luIDwtIHBsb3RfcmVwcmVzZW50YXRpb24oc2NoZW1hX2V4cGVydHNfaW4sIHRyaWFkX3ZhbHVlKSArCiAgZ2d0aXRsZSgiVHJpYWQgQ29tcGxldGlvbiIpCgpwbG90X2NvbW1faW4gPC0gcGxvdF9yZXByZXNlbnRhdGlvbihzY2hlbWFfZXhwZXJ0c19pbiwgY29tbV92YWx1ZSkgKwogIGdndGl0bGUoIkNvbW11bml0eSBEZXRlY3Rpb24iKQoKcGxvdF9zY2hlbWFzX2luIDwtICgKICBwbG90X2Nob2ljZSB8IHBsb3RfbWVtX2luIHwgcGxvdF90cmlhZF9pbiB8IHBsb3RfY29tbV9pbgopICsKICBwbG90X2Fubm90YXRpb24oCiAgICB0aXRsZSA9ICJBZHZpc29ycyBvYnNlcnZlIGFkdmlzZWVzJyBhZHZpc2VlcyIsCiAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSkpCiAgKQoKcGxvdF9zY2hlbWFzX2luCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic2NoZW1hX2dhbGxlcnlfaW4ucGRmIiksCiAgICBwbG90X3NjaGVtYXNfaW4sCiAgICB3aWR0aCA9IDEyLCBoZWlnaHQgPSA0LAogICAgZGV2aWNlID0gY2Fpcm9fcGRmLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCkF0IHRoZSBncm91cC1sZXZlbC4uLiBzY2hlbWFzIG1ha2UgZnJhbmtseSB0ZXJyaWJsZSBwcmVkaWN0aW9ucywgbm8gbWF0dGVyIHdoYXQgd2UgYXNzdW1lIGFib3V0IG9ic2VydmF0aW9ucy4gTm90ZSB0aGF0IGlmIGEgcGFydGljdWxhciBzdWJqZWN0IGlzIHByZWRpY3RlZCB0byBhc2sgYWxsIG90aGVyIG1hbmFnZXJzIGZvciBhZHZpY2UsIHRoZSByb3cgYXNzb2NpYXRlZCB3aXRoIHRoYXQgc3ViamVjdCB3aWxsIGJlIGZpbGxlZCB3aXRoIGEgdmFsdWUgY2xvc2UgdG8gMS8yMD0wLjA1LiBTbyB3ZSBjYW4gc2VlIHRoYXQgdGhlIHRyaWFkIGNvbXBsZXRpb24gc3RyYXRlZ3kgcHJlZGljdHMgdGhhdCBtb3N0IG1hbmFnZXJzIGFyZSBjb25uZWN0ZWQsIGFuZCB0aGUgY29tbXVuaXR5IGRldGVjdGlvbiBzdHJhdGVneSBwcmVkaWN0cyB0aGF0IGxpdGVyYWxseSBhbGwgbWFuYWdlcnMgYXJlIGNvbm5lY3RlZC4gTmVpdGhlciBjb21lcyBldmVuIGEgbGl0dGxlIGJpdCBjbG9zZSB0byB0aGUgYWN0dWFsIGFsbG9jZW50cmljIG5ldHdvcmsgcmVwcmVzZW50YXRpb24uCgoKIyBTdWNjZXNzb3IgcmVwZXNlbnRhdGlvbgoKTGV0J3Mgc2F5IHBlb3BsZSB1c2UgbXVsdGlzdGVwIHJlbGF0aW9uYWwgYWJzdHJhY3Rpb24gdG8gcmVwcmVzZW50IG5ldHdvcmtzLCBhbmQgbGV0J3MgdXNlIHRoZSBTUiB0byBhcHByb3hpbWF0ZSB0aGF0IGtpbmQgb2YgYWJzdHJhY3Rpb24uIFVzaW5nIHRoZSBvYnNlcnZhdGlvbnMgd2UgZ2VuZXJhdGVkIGJlZm9yZSwgbGV0J3MgY3JlYXRlIGxvdHMgb2YgbGVhcm5pbmcgInRyaWFscyIgdG8gdHJhaW4gdGhlIGFsZ29yaXRobS4KCmBgYHtyIGNyZWF0ZS1zci1vYnN9CnNyX29ic2VydmF0aW9uc19hbGwgPC0gb2JzX2VkZ2VsaXN0X2FsbCAlPiUKICAjIENyZWF0ZSBzaW11bGF0ZWQgImxlYXJuaW5nIHRyaWFscyIgdG8gdHJhaW4gYW4gYXN5bXB0b3RpYyBTUgogIGV4cGFuZF9ncmlkKHJlcCA9IDE6MTAwKSAlPiUKICAjIFJhbmRvbWl6ZSAib3JkZXIgb2YgdHJpYWxzIiBwZXIgcmVwZXRpdGlvbgogIGdyb3VwX2J5KHN1Yl9pZCwgcmVwKSAlPiUKICBzbGljZV9zYW1wbGUocHJvcCA9IDEpICU+JQogIHVuZ3JvdXAoKQoKc3Jfb2JzZXJ2YXRpb25zX291dCA8LSBvYnNfZWRnZWxpc3Rfb3V0ICU+JQogIGV4cGFuZF9ncmlkKHJlcCA9IDE6MTAwKSAlPiUKICBncm91cF9ieShzdWJfaWQsIHJlcCkgJT4lCiAgc2xpY2Vfc2FtcGxlKHByb3AgPSAxKSAlPiUKICB1bmdyb3VwKCkKCnNyX29ic2VydmF0aW9uc19pbiA8LSBvYnNfZWRnZWxpc3RfaW4gJT4lCiAgZXhwYW5kX2dyaWQocmVwID0gMToxMDApICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgcmVwKSAlPiUKICBzbGljZV9zYW1wbGUocHJvcCA9IDEpICU+JQogIHVuZ3JvdXAoKQpgYGAKCkFuZCBub3cgd2UgY2FuIHVzZSB0aG9zZSB0byBidWlsZCBTUnMgYXQgZGlmZmVyZW50IHNjYWxlcy4gV2UnbGwgYXNzdW1lIHRoYXQgZXZlcnkgc3ViamVjdCBpcyB1c2luZyB0aGUgc2FtZSBzdWNjZXNzb3IgaG9yaXpvbi4uLgoKYGBge3IgY29tcHV0ZS1zcn0Kc3JfYWxsIDwtIHNyX29ic2VydmF0aW9uc19hbGwgJT4lCiAgZXhwYW5kX2dyaWQoZ2FtbWEgPSBzZXEoMC4xLCAwLjksIDAuMSksIC4pICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgZ2FtbWEpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoCiAgICBzciA9IG1hcDIoCiAgICAgIC54ID0gZGF0YSwgLnkgPSBnYW1tYSwKICAgICAgfmJ1aWxkX3JlcF9zcigueCwgdGhpc19hbHBoYSA9IDAuMSwgdGhpc19nYW1tYSA9IC55KQogICAgKQogICkgJT4lCiAgdW5uZXN0KHNyKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1kYXRhKSAlPiUKICBtdXRhdGUoZ2FtbWEgPSBnYW1tYSAqIDEwKSAlPiUKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBnYW1tYSwKICAgIG5hbWVzX3ByZWZpeCA9ICJzciIsCiAgICB2YWx1ZXNfZnJvbSA9IHNyX3ZhbHVlCiAgKQoKc3Jfb3V0IDwtIHNyX29ic2VydmF0aW9uc19vdXQgJT4lCiAgZXhwYW5kX2dyaWQoZ2FtbWEgPSBzZXEoMC4xLCAwLjksIDAuMSksIC4pICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgZ2FtbWEpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoCiAgICBzciA9IG1hcDIoCiAgICAgIC54ID0gZGF0YSwgLnkgPSBnYW1tYSwKICAgICAgfmJ1aWxkX3JlcF9zcigueCwgdGhpc19hbHBoYSA9IDAuMSwgdGhpc19nYW1tYSA9IC55KQogICAgKQogICkgJT4lCiAgdW5uZXN0KHNyKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1kYXRhKSAlPiUKICBtdXRhdGUoZ2FtbWEgPSBnYW1tYSAqIDEwKSAlPiUKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBnYW1tYSwKICAgIG5hbWVzX3ByZWZpeCA9ICJzciIsCiAgICB2YWx1ZXNfZnJvbSA9IHNyX3ZhbHVlCiAgKQoKc3JfaW4gPC0gc3Jfb2JzZXJ2YXRpb25zX2luICU+JQogIGV4cGFuZF9ncmlkKGdhbW1hID0gc2VxKDAuMSwgMC45LCAwLjEpLCAuKSAlPiUKICBncm91cF9ieShzdWJfaWQsIGdhbW1hKSAlPiUKICBuZXN0KCkgJT4lCiAgbXV0YXRlKAogICAgc3IgPSBtYXAyKAogICAgICAueCA9IGRhdGEsIC55ID0gZ2FtbWEsCiAgICAgIH5idWlsZF9yZXBfc3IoLngsIHRoaXNfYWxwaGEgPSAwLjEsIHRoaXNfZ2FtbWEgPSAueSkKICAgICkKICApICU+JQogIHVubmVzdChzcikgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtZGF0YSkgJT4lCiAgbXV0YXRlKGdhbW1hID0gZ2FtbWEgKiAxMCkgJT4lCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gZ2FtbWEsCiAgICBuYW1lc19wcmVmaXggPSAic3IiLAogICAgdmFsdWVzX2Zyb20gPSBzcl92YWx1ZQogICkKYGBgCgpMZXQncyBnZXQgYSBzZW5zZSBmb3IgdGhlIHByZWRpY3Rpb25zIHdoZW4gdGhlIFNSIGlzIHRyYWluZWQgb24gb2JzZXJ2YXRpb25zIHRoYXQgZ28gYm90aCB3YXlzLgoKYGBge3IgcGxvdC1zci1hbGx9CnBsb3Rfc3IxX2FsbCA8LSBzcl9hbGwgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMSwgbl9icmVha3MgPSA0KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC4xIikKCnBsb3Rfc3IzX2FsbCA8LSBzcl9hbGwgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMykgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuMyIpCgpwbG90X3NyNV9hbGwgPC0gc3JfYWxsICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjUpICsKICBnZ3RpdGxlKCJcdTAzQjMgPSAwLjUiKQoKcGxvdF9zcjdfYWxsIDwtIHNyX2FsbCAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3I3KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC43IikKCnBsb3Rfc3I5X2FsbCA8LSBzcl9hbGwgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyOSkgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuOSIpCgpwbG90X3NyX2dhbGxlcnlfYWxsIDwtICgKICBwbG90X2Nob2ljZSArCiAgICBwbG90X3NyMV9hbGwgKyBwbG90X3NyM19hbGwgKyBwbG90X3NyNV9hbGwgKyBwbG90X3NyN19hbGwgKyBwbG90X3NyOV9hbGwKKQoKcGxvdF9zcl9nYWxsZXJ5X2FsbAoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IiwgInNyX2dhbGxlcnlfYWxsLnBkZiIpLAogICAgcGxvdF9zcl9nYWxsZXJ5X2FsbCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKQW5kIG5vdyB3aGVyZSBhZHZpc2VlcyBvYnNlcnZlIHRoZWlyIGFkdmlzb3JzJyBhZHZpc29ycy4uLgoKYGBge3IgcGxvdC1zci1vdXR9CnBsb3Rfc3IxX291dCA8LSBzcl9vdXQgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMSwgbl9icmVha3MgPSA0KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC4xIikKCnBsb3Rfc3IzX291dCA8LSBzcl9vdXQgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMykgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuMyIpCgpwbG90X3NyNV9vdXQgPC0gc3Jfb3V0ICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjUpICsKICBnZ3RpdGxlKCJcdTAzQjMgPSAwLjUiKQoKcGxvdF9zcjdfb3V0IDwtIHNyX291dCAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3I3KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC43IikKCnBsb3Rfc3I5X291dCA8LSBzcl9vdXQgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyOSkgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuOSIpCgpwbG90X3NyX2dhbGxlcnlfb3V0IDwtICgKICBwbG90X2Nob2ljZSArCiAgICBwbG90X3NyMV9vdXQgKyBwbG90X3NyM19vdXQgKyBwbG90X3NyNV9vdXQgKyBwbG90X3NyN19vdXQgKyBwbG90X3NyOV9vdXQKKQoKcGxvdF9zcl9nYWxsZXJ5X291dAoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IiwgInNyX2dhbGxlcnlfb3V0LnBkZiIpLAogICAgcGxvdF9zcl9nYWxsZXJ5X291dCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKQW5kIGZpbmFsbHkgd2hlcmUgYWR2aXNvcnMgb2JzZXJ2ZSB0aGVpciBhZHZpc2VlcycgYWR2aXNlZXMuLi4KCmBgYHtyIHBsb3Qtc3ItaW59CnBsb3Rfc3IxX2luIDwtIHNyX2luICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjEsIG5fYnJlYWtzID0gNCkgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuMSIpCgpwbG90X3NyM19pbiA8LSBzcl9pbiAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3IzKSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC4zIikKCnBsb3Rfc3I1X2luIDwtIHNyX2luICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjUpICsKICBnZ3RpdGxlKCJcdTAzQjMgPSAwLjUiKQoKcGxvdF9zcjdfaW4gPC0gc3JfaW4gJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyNykgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuNyIpCgpwbG90X3NyOV9pbiA8LSBzcl9pbiAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3I5KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC45IikKCnBsb3Rfc3JfZ2FsbGVyeV9pbiA8LSAoCiAgcGxvdF9jaG9pY2UgKwogICAgcGxvdF9zcjFfaW4gKyBwbG90X3NyM19pbiArIHBsb3Rfc3I1X2luICsgcGxvdF9zcjdfaW4gKyBwbG90X3NyOV9pbgopCgpwbG90X3NyX2dhbGxlcnlfaW4KCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJzcl9nYWxsZXJ5X2luLnBkZiIpLAogICAgcGxvdF9zcl9nYWxsZXJ5X2luLAogICAgd2lkdGggPSAxMiwgaGVpZ2h0ID0gOCwKICAgIGRldmljZSA9IGNhaXJvX3BkZiwgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgoKIyBTdGF0aXN0aWNhbCB0ZXN0cwoKT2theSwgbm93IHRoYXQgd2UgaGF2ZSBhbGwgb2YgdGhlIHByZWRpY3RlZCBzdHJhdGVnaWVzIGluIGhhbmQsIHdlJ2xsIHdhbnQgdG8gcGVyZm9ybSBzb21lIGZvcm1hbCBzdGF0aXN0aWNhbCB0ZXN0cyB0byB2ZXJpZnkgdGhhdCB0aGUgU1IgaXMgdHJ1bHkgZG9pbmcgdGhlIGJlc3QgYXQgZXhwbGFpbmluZyBzdWJqZWN0cycgbmV0d29yayByZXByZXNlbnRhdGlvbnMuIExldCdzIGNyZWF0ZSBhIGRhdGFmcmFtZSB3aXRoIGFsbCBvZiB0aGUgaW5mbyB3ZSdsbCBuZWVkLgoKYGBge3IgZGVmaW5lLXRlc3QtZGF0YXNldH0KdGVzdF9kYXRhc2V0X2FsbCA8LSBrcmFja2hhcmR0X2FsbG9jZW50cmljICU+JQogIHJlbmFtZShjaG9pY2UgPSBlZGdlKSAlPiUKICBsZWZ0X2pvaW4oc2NoZW1hX2V4cGVydHNfYWxsLCBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikpICU+JQogIGxlZnRfam9pbihzcl9hbGwsIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKSkKCnRlc3RfZGF0YXNldF9vdXQgPC0ga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICByZW5hbWUoY2hvaWNlID0gZWRnZSkgJT4lCiAgbGVmdF9qb2luKHNjaGVtYV9leHBlcnRzX291dCwgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpKSAlPiUKICBsZWZ0X2pvaW4oc3Jfb3V0LCBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikpCgp0ZXN0X2RhdGFzZXRfaW4gPC0ga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICByZW5hbWUoY2hvaWNlID0gZWRnZSkgJT4lCiAgbGVmdF9qb2luKHNjaGVtYV9leHBlcnRzX2luLCBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikpICU+JQogIGxlZnRfam9pbihzcl9pbiwgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpKQpgYGAKCldlJ2xsIGRvIGFsbCBvZiB0aGUgc3RhdGlzdGljYWwgdGVzdHMgZm9yIHRoZSAib2JzZXJ2YXRpb25zIGdvIGJvdGggd2F5cyIgbW9kZWxzLiBOb3RlIHRoYXQgd2UgY2FuJ3QgYWN0dWFsbHkgZXN0aW1hdGUgYSBtb2RlbCBmb3IgY29tbXVuaXR5IGRldGVjdGlvbiwgYXMgdGhpcyBzdHJhdGVneSBwcmVkaWN0cyB0aGF0IGV2ZXJ5b25lIGlzIGNvbm5lY3RlZCB0byBldmVyeW9uZS4KCmBgYHtyIHRlc3Qtb2JzLWFsbH0KdGVzdF9tZW1fYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyAoMSArIG1lbV92YWx1ZSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3RfdHJpYWRfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyB0cmlhZF92YWx1ZSArICgxICsgdHJpYWRfdmFsdWUgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgojIHRlc3RfY29tbV9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKIyAgIGdsbWVyKAojICAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBjb21tX3ZhbHVlICsgKDEgKyBjb21tX3ZhbHVlIHwgc3ViX2lkKSwKIyAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KIyAgICkKCnRlc3Rfc3IxX2FsbCA8LSB0ZXN0X2RhdGFzZXRfYWxsICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3IxICsgKDEgKyBzcjEgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyMl9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyMiArICgxICsgc3IyIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjNfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjMgKyAoMSArIHNyMyB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I0X2FsbCA8LSB0ZXN0X2RhdGFzZXRfYWxsICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I0ICsgKDEgKyBzcjQgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyNV9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNSArICgxICsgc3I1IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjZfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjYgKyAoMSArIHNyNiB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I3X2FsbCA8LSB0ZXN0X2RhdGFzZXRfYWxsICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I3ICsgKDEgKyBzcjcgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyOF9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyOCArICgxICsgc3I4IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjlfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjkgKyAoMSArIHNyOSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKYGBgCgpNb3Zpbmcgb24gdG8gdGhlICJhZHZpc2VlcyBvYnNlcnZlIGFkdmlzb3JzJyBhZHZpc29ycyIgbW9kZWxzLgoKYGBge3IgdGVzdC1vYnMtb3V0fQp0ZXN0X21lbV9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArICgxICsgbWVtX3ZhbHVlIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF90cmlhZF9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHRyaWFkX3ZhbHVlICsgKDEgKyB0cmlhZF92YWx1ZSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3RfY29tbV9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIGNvbW1fdmFsdWUgKyAoMSArIGNvbW1fdmFsdWUgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyMV9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyMSArICgxICsgc3IxIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjJfb3V0IDwtIHRlc3RfZGF0YXNldF9vdXQgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjIgKyAoMSArIHNyMiB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3IzX291dCA8LSB0ZXN0X2RhdGFzZXRfb3V0ICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3IzICsgKDEgKyBzcjMgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyNF9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNCArICgxICsgc3I0IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjVfb3V0IDwtIHRlc3RfZGF0YXNldF9vdXQgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjUgKyAoMSArIHNyNSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I2X291dCA8LSB0ZXN0X2RhdGFzZXRfb3V0ICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I2ICsgKDEgKyBzcjYgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyN19vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNyArICgxICsgc3I3IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjhfb3V0IDwtIHRlc3RfZGF0YXNldF9vdXQgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjggKyAoMSArIHNyOCB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I5X291dCA8LSB0ZXN0X2RhdGFzZXRfb3V0ICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I5ICsgKDEgKyBzcjkgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCmBgYAoKRmluYWxseSwgdGhlICJhZHZpc29ycyBvYnNlcnZlIGFkdmlzZWVzJyBhZHZpc2VlcyIgbW9kZWxzLiBPbmNlIGFnYWluLCB3ZSBjYW4ndCBlc3RpbWF0ZSBhIG1vZGVsIGZvciBjb21tdW5pdHkgZGV0ZWN0aW9uLCBhcyB0aGlzIHN0cmF0ZWd5IHByZWRpY3RzIHRoYXQgZXZlcnlvbmUgaXMgY29ubmVjdGVkIHRvIGV2ZXJ5b25lLgoKYGBge3IgdGVzdC1vYnMtaW59CnRlc3RfbWVtX2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArICgxICsgbWVtX3ZhbHVlIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF90cmlhZF9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyB0cmlhZF92YWx1ZSArICgxICsgdHJpYWRfdmFsdWUgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgojIHRlc3RfY29tbV9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiMgICBnbG1lcigKIyAgICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgY29tbV92YWx1ZSArICgxICsgY29tbV92YWx1ZSB8IHN1Yl9pZCksCiMgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiMgICApCgp0ZXN0X3NyMV9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjEgKyAoMSArIHNyMSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3IyX2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyMiArICgxICsgc3IyIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjNfaW4gPC0gdGVzdF9kYXRhc2V0X2luICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3IzICsgKDEgKyBzcjMgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyNF9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjQgKyAoMSArIHNyNCB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I1X2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNSArICgxICsgc3I1IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjZfaW4gPC0gdGVzdF9kYXRhc2V0X2luICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I2ICsgKDEgKyBzcjYgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyN19pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjcgKyAoMSArIHNyNyB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I4X2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyOCArICgxICsgc3I4IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjlfaW4gPC0gdGVzdF9kYXRhc2V0X2luICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I5ICsgKDEgKyBzcjkgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCmBgYAoKT2YgYWxsIG9mIHRoZXNlIG1vZGVscywgd2hpY2ggaGFzIHRoZSAiYmVzdCIgZml0LCBiYXNlZCBvbiBCSUM/CgpgYGB7ciBnb29kbmVzcy1vZi1maXR9CiMgV2hpY2ggaGFzIHRoZSBiZXN0ICJnb29kbmVzcy1vZi1maXQiPwpnb29kbmVzc19vZl9maXQgPC0gYmluZF9yb3dzKAogICMgQWxsOiBnb2VzIGJvdGggd2F5cwogIGdsYW5jZSh0ZXN0X21lbV9hbGwpICU+JSBtdXRhdGUobW9kZWwgPSAibWVtX2FsbCIpLAogIGdsYW5jZSh0ZXN0X3RyaWFkX2FsbCkgJT4lIG11dGF0ZShtb2RlbCA9ICJ0cmlhZF9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjFfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMV9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjJfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMl9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjNfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyM19hbGwiKSwKICBnbGFuY2UodGVzdF9zcjRfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNF9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjVfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNV9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjZfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNl9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjdfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyN19hbGwiKSwKICBnbGFuY2UodGVzdF9zcjhfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOF9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjlfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOV9hbGwiKSwKICAjIE91dDogYWR2aXNvcnMgb2YgYWR2aXNvcnMKICBnbGFuY2UodGVzdF9tZW1fb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gIm1lbV9vdXQiKSwKICBnbGFuY2UodGVzdF90cmlhZF9vdXQpICU+JSBtdXRhdGUobW9kZWwgPSAidHJpYWRfb3V0IiksCiAgZ2xhbmNlKHRlc3RfY29tbV9vdXQpICU+JSBtdXRhdGUobW9kZWwgPSAiY29tbV9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjFfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMV9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjJfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMl9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjNfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyM19vdXQiKSwKICBnbGFuY2UodGVzdF9zcjRfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNF9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjVfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNV9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjZfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNl9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjdfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyN19vdXQiKSwKICBnbGFuY2UodGVzdF9zcjhfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOF9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjlfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOV9vdXQiKSwKICAjIEluOiBhZHZpc2VlcyBvZiBhZHZpc2VlcwogIGdsYW5jZSh0ZXN0X21lbV9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJtZW1faW4iKSwKICBnbGFuY2UodGVzdF90cmlhZF9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJ0cmlhZF9pbiIpLAogIGdsYW5jZSh0ZXN0X3NyMV9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJzcjFfaW4iKSwKICBnbGFuY2UodGVzdF9zcjJfaW4pICU+JSBtdXRhdGUobW9kZWwgPSAic3IyX2luIiksCiAgZ2xhbmNlKHRlc3Rfc3IzX2luKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyM19pbiIpLAogIGdsYW5jZSh0ZXN0X3NyNF9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJzcjRfaW4iKSwKICBnbGFuY2UodGVzdF9zcjVfaW4pICU+JSBtdXRhdGUobW9kZWwgPSAic3I1X2luIiksCiAgZ2xhbmNlKHRlc3Rfc3I2X2luKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNl9pbiIpLAogIGdsYW5jZSh0ZXN0X3NyN19pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJzcjdfaW4iKSwKICBnbGFuY2UodGVzdF9zcjhfaW4pICU+JSBtdXRhdGUobW9kZWwgPSAic3I4X2luIiksCiAgZ2xhbmNlKHRlc3Rfc3I5X2luKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOV9pbiIpLAopICU+JQogIHNlbGVjdChtb2RlbCwgZXZlcnl0aGluZygpKSAlPiUKICBhcnJhbmdlKEJJQykgJT4lCiAgIyBNYWtlIHRoaXMgYSBsaXR0bGUgbW9yZSBodW1hbi1yZWFkYWJsZQogIHNlcGFyYXRlKG1vZGVsLCBpbnRvID0gYygibW9kZWwiLCAiZGlyZWN0aW9uIikpICU+JQogIG11dGF0ZSgKICAgIGRpcmVjdGlvbiA9IGNhc2Vfd2hlbigKICAgICAgZGlyZWN0aW9uID09ICJvdXQiIH4gImFkdmlzZWUgb2JzZXJ2ZXMgYWR2aXNvciBvZiBhZHZpc29yIiwKICAgICAgZGlyZWN0aW9uID09ICJpbiIgfiAiYWR2aXNvciBvYnNlcnZlcyBhZHZpc2VlIG9mIGFkdmlzZWUiLAogICAgICBkaXJlY3Rpb24gPT0gImFsbCIgfiAiYm90aCB3YXlzIgogICAgKQogICkKCmdvb2RuZXNzX29mX2ZpdCAlPiUKICBtdXRhdGUoCiAgICBtb2RlbCA9IGZjdF9yZWxldmVsKAogICAgICBtb2RlbCwKICAgICAgInNyMSIsICJzcjIiLCAic3IzIiwgInNyNCIsICJzcjUiLCAic3I2IiwgInNyNyIsICJzcjgiLCAic3I5IiwKICAgICAgIm1lbSIsICJ0cmlhZCIsICJjb21tIgogICAgKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbW9kZWwsIHkgPSBCSUMsIGNvbG9yID0gZGlyZWN0aW9uKSkgKwogIGdnICsKICBnZW9tX3BvaW50KCkgKwogIGdndGl0bGUoIk1vZGVsIGdvb2RuZXNzLW9mLWZpdCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmdvb2RuZXNzX29mX2ZpdCAlPiUKICBrYWJsZSgpCmBgYAoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGJlc3QtZml0dGluZyBtb2RlbCBlc3RpbWF0ZXM6CgpgYGB7ciBiZXN0LW1vZGVsfQp0ZXN0X3NyN19vdXQgJT4lCiAgdGlkeShjb25mLmludCA9IFRSVUUpICU+JQogIGthYmxlKCkKCnZpZih0ZXN0X3NyN19vdXQpCmBgYAoKCgojIFNSIGNlbnRyYWxpdHkKCkNhbiB0aGUgYmVzdC1maXR0aW5nIFNSIGV4cGxhaW4gYW4gaW5kaXZpZHVhbCdzIHBlcmNlcHRpb25zIG9mIG90aGVyIG5ldHdvcmsgbWVtYmVycycgY2VudHJhbGl0eT8KCmBgYHtyIGRlZi1zci1jZW50cmFsaXR5fQpzcl9jZW50cmFsaXR5IDwtIHNyX291dCAlPiUKICAjIFNSIGNlbnRyYWxpdHkgZnJvbSBiZXN0IHZhcmlhbnQKICBmaWx0ZXIoZnJvbSAhPSB0bykgJT4lCiAgZ3JvdXBfYnkoc3ViX2lkLCBub2RlX2lkID0gdG8pICU+JQogIHN1bW1hcmlzZShzcl9jZW50cmFsaXR5ID0gbWVhbihzcjcpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICAjIFBlcmNlaXZlZCBjZW50cmFsaXR5CiAgbGVmdF9qb2luKAogICAga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICAgICAgZ3JvdXBfYnkoc3ViX2lkLCBub2RlX2lkID0gdG8pICU+JQogICAgICBzdW1tYXJpc2UocGVyY2VpdmVkX2NlbnRyYWxpdHkgPSBtZWFuKGVkZ2UpLCAuZ3JvdXBzID0gImRyb3AiKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgIm5vZGVfaWQiKQogICkKYGBgCgpUbyBhbnN3ZXIgdGhpcywgd2UnbGwgZG8gYSByYW5kb20tZWZmZWN0cyBhbmFseXNpcyB3aGVyZSB3ZSB0YWtlIGVhY2ggaW5kaXZpZHVhbCdzIGlkaW9zeW5jcmF0aWMgbWVudGFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZWlyIG5ldHdvcmssIHRoZW4gcmFuay1jb3JyZWxhdGUgaXQgd2l0aCB0aGUgU1IncyBpbmRpdmlkdWFsLWxldmVsIHByZWRpY3Rpb25zLgoKYGBge3IgdGVzdC1zci1jZW50cmFsaXR5fQpzcl9jZW50cmFsaXR5X2NvcnIgPC0gc3JfY2VudHJhbGl0eSAlPiUKICBncm91cF9ieShzdWJfaWQpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoCiAgICBzcGVhcm1hbiA9IG1hcF9kYmwoCiAgICAgIC54ID0gZGF0YSwKICAgICAgLmYgPSB+d2l0aCgKICAgICAgICAueCwgY29yKHNyX2NlbnRyYWxpdHksIHBlcmNlaXZlZF9jZW50cmFsaXR5LCBtZXRob2QgPSAic3BlYXJtYW4iKQogICAgICApCiAgICApCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1kYXRhKQoKc3JfY2VudHJhbGl0eV9jb3JyICU+JQogIG11dGF0ZShzcGVhcm1hbiA9IHRhbmgoc3BlYXJtYW4pKSAlPiUKICBzZWxlY3Qoc3BlYXJtYW4pICU+JQogIGRlZnJhbWUoKSAlPiUKICB0LnRlc3QoKSAlPiUKICB0aWR5KCkgJT4lCiAga2FibGUoCiAgICBjYXB0aW9uID0gc3RyX2MoCiAgICAgICJ0LXRlc3Qgb2YgdGhlIGF2ZXJhZ2UgU3BlYXJtYW4gY29ycmVsYXRpb24gYmV0d2VlbiBwZXJjZWl2ZWQgYW5kICIsCiAgICAgICJTUi1wcmVkaWN0ZWQgY2VudHJhbGl0eSAoei10cmFuc2Zvcm1lZCkiCiAgICApCiAgKQoKc3JfY2VudHJhbGl0eV9jb3JyICU+JQogIHN1bW1hcmlzZShtZWFuX3NwZWFybWFuID0gbWVhbihzcGVhcm1hbikpICU+JQogIGthYmxlKCkKYGBgCgpMZXQncyB0cnkgdG8gdmlzdWFsaXplIHRoZXNlIHJlc3VsdHMgaW4gYW4gaW50dWl0aXZlIGZvcm1hdC4KCmBgYHtyIHBsb3Qtc3ItY2VudHJhbGl0eX0KcGxvdF9zcl9jZW50cmFsaXR5X2dyb3VwIDwtIHNyX2NlbnRyYWxpdHkgJT4lCiAgIyBHZXQgZWFjaCBzdWJqZWN0J3MgcmFuay1vcmRlcmVkIHBlcmNlaXZlZCBhbmQgU1ItcHJlZGljdGVkIGNlbnRyYWxpdHkKICBncm91cF9ieShzdWJfaWQpICU+JQogIG11dGF0ZShhY3Jvc3MoZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLCB+cmFuaygueCwgdGllcy5tZXRob2QgPSAibWluIikpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBBdmVyYWdlIGFjcm9zcyBzdWJqZWN0cyB0byBnZXQgZ3JvdXAtbGV2ZWwgcmVzdWx0cwogIGdyb3VwX2J5KG5vZGVfaWQpICU+JQogIHN1bW1hcmlzZShhY3Jvc3MoZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLCBtZWFuKSkgJT4lCiAgIyBGb3IgY29sb3ItY29kaW5nIHR3byBwYWlycyBvZiBtYW5hZ2VycyB3aXRoIGVxdWl2YWxlbnQgZGVncmVlIGNlbnRyYWxpdHksCiAgIyBidXQgZGlmZmVyZW50IHBlcmNlaXZlZCBjZW50cmFsaXR5CiAgbXV0YXRlKAogICAgY29sb3Jjb2RlID0gY2FzZV93aGVuKAogICAgICBub2RlX2lkICVpbiUgYygxLCA3KSB+ICJhIiwKICAgICAgbm9kZV9pZCAlaW4lIGMoMTgsIDIxKSB+ICJiIgogICAgKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4PXBlcmNlaXZlZF9jZW50cmFsaXR5LCB5PXNyX2NlbnRyYWxpdHkpKSArCiAgZ2cgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gbm9kZV9pZCwgZmlsbCA9IGNvbG9yY29kZSksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYTZjZWUzIiwgIiNiMmRmOGEiKSwgbmEudmFsdWUgPSAiZ3JleTk1IikgKwogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIlBlcmNlaXZlZCBjZW50cmFsaXR5IChyYW5rLW9yZGVyZWQpIikgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlNSIGNlbnRyYWxpdHkgKHJhbmstb3JkZXJlZCkiKSArCiAgZ2d0aXRsZSgiUGVyY2VpdmVkIHZzIFN1Y2Nlc3NvciBDZW50cmFsaXR5IChHcm91cC1MZXZlbCkiKQoKcGxvdF9zcl9jZW50cmFsaXR5X2dyb3VwCgpwbG90X3NyX2NlbnRyYWxpdHlfaW5kaXZpZHVhbCA8LSBzcl9jZW50cmFsaXR5ICU+JQogICMgR2V0IGVhY2ggc3ViamVjdCdzIHJhbmstb3JkZXJlZCBwZXJjZWl2ZWQgYW5kIFNSLXByZWRpY3RlZCBjZW50cmFsaXR5CiAgZ3JvdXBfYnkoc3ViX2lkKSAlPiUKICBtdXRhdGUoYWNyb3NzKGVuZHNfd2l0aCgiX2NlbnRyYWxpdHkiKSwgfnJhbmsoLngsIHRpZXMubWV0aG9kID0gIm1pbiIpKSkgJT4lCiAgdW5ncm91cCgpICU+JQogICMgRm9ybWF0dGluZyBmb3IgcGxvdHRpbmcKICBwaXZvdF9sb25nZXIoCiAgICBlbmRzX3dpdGgoIl9jZW50cmFsaXR5IiksCiAgICBuYW1lc190byA9ICJtZXRyaWMiLAogICAgdmFsdWVzX3RvID0gImNlbnRyYWxpdHkiCiAgKSAlPiUKICBtdXRhdGUoCiAgICBub2RlX2lkID0gZmFjdG9yKG5vZGVfaWQpLAogICAgc3ViX2lkID0gc3RyX3BhZChzdWJfaWQsIHdpZHRoID0gMiwgc2lkZSA9ICJsZWZ0IiwgcGFkID0gIjAiKSwKICAgIHN1Yl9pZCA9IHN0cl9jKCJNYW5hZ2VyICIsIHN1Yl9pZCkKICApICU+JQogIGdncGxvdChhZXMoeD1ub2RlX2lkLCB5PWNlbnRyYWxpdHksIGZpbGw9bWV0cmljKSkgKwogIGZhY2V0X3dyYXAofnN1Yl9pZCwgbnJvdyA9IDMpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjUpICsKICBjb29yZF9wb2xhcigpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgKICAgIG5hbWUgPSAiQ2VudHJhbGl0eSIsCiAgICBsYWJlbHMgPSBjKCJQZXJjZWl2ZWQgKEVtcGlyaWNhbCkiLCAiU3VjY2Vzc29yIFJlcHJlc2VudGF0aW9uIChTaW11bGF0ZWQpIikKICApICsKICBnZ3RpdGxlKCJQZXJjZWl2ZWQgdnMgU3VjY2Vzc29yIENlbnRyYWxpdHkgKEluZGl2aWR1YWwtTGV2ZWwpIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEzKSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMSksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC43NSwgImxpbmVzIiksCiAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKGMoMCwgMCwgMCwgMCksIHVuaXQgPSAibGluZXMiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCgpwbG90X3NyX2NlbnRyYWxpdHlfaW5kaXZpZHVhbAoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IiwgInNyX2NlbnRyYWxpdHlfaW5kaXZpZHVhbF9zdGFuZGFyZC5wZGYiKSwKICAgIHBsb3QgPSBwbG90X3NyX2NlbnRyYWxpdHlfaW5kaXZpZHVhbCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKV2UncmUgcGFydGljdWxhcmx5IGludGVyZXN0ZWQgaW4gdGhlIG1hbmFnZXIgcGFpcnMgMS03IGFuZCAxOC0yMS4gT24gYW4gaW5kaXZpZHVhbC1ieS1pbmRpdmlkdWFsIGJhc2lzLCBkb2VzIHRoZSBtb2RlbCBjb3JyZWN0bHkgcHJlZGljdCwgaW4gZWFjaCBwYWlyLCB3aGljaCBtYW5hZ2VyIGlzIHJlcHJlc2VudGVkIGFzIGJlaW5nIG1vcmUgY2VudHJhbD8gV2UnbGwgZG8gYSBwcmV2YWxlbmNlIHRlc3QgdG8gc2VlIHdoZXRoZXIgdGhlIG1vZGVsIG1hZGUgY29ycmVjdCBwcmVkaWN0aW9ucyBmb3Igc2lnbmlmaWNhbnRseSBncmVhdGVyIHRoYW4gNTAlIG9mIHN1YmplY3RzLgoKYGBge3IgcHJldmFsZW5jZS10ZXN0fQpzcl9jZW50cmFsaXR5ICU+JQogICMgRmluZCBhbmQgcmV0YWluIG9ubHkgcmVsZXZhbnQgbm9kZS1wYWlycwogIG11dGF0ZSgKICAgIHBhaXJfaWQgPSBjYXNlX3doZW4oCiAgICAgIG5vZGVfaWQgJWluJSBjKDEsIDcpIH4gIjEtNyIsCiAgICAgIG5vZGVfaWQgJWluJSBjKDE4LCAyMSkgfiAiMTgtMjEiCiAgICApCiAgKSAlPiUKICBkcm9wX25hKCkgJT4lCiAgIyBXaGljaGV2ZXIgbWFuYWdlciBpcyByZXByZXNlbnRlZCBhcyBiZWluZyBtb3JlIGNlbnRyYWwgaW4gZWFjaCBub2RlLXBhaXIsCiAgIyBkb2VzIHRoZSBtb2RlbCBtYWtlIGEgY29ycmVjdCBwcmVkaWN0aW9uPwogIGdyb3VwX2J5KHN1Yl9pZCwgcGFpcl9pZCkgJT4lCiAgbXV0YXRlKAogICAgYWNyb3NzKAogICAgICBjKHNyX2NlbnRyYWxpdHksIHBlcmNlaXZlZF9jZW50cmFsaXR5KSwKICAgICAgfi54IC0gZmlyc3QoLngpCiAgICApCiAgKSAlPiUKICBmaWx0ZXIobm9kZV9pZCAlaW4lIGMoNywgMjEpKSAlPiUKICBzdW1tYXJpc2UoCiAgICBjb3JyZWN0ID0gc3JfY2VudHJhbGl0eSAqIHBlcmNlaXZlZF9jZW50cmFsaXR5ID4gMCwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApICU+JQogICMgVGFsbHkgY29ycmVjdCBwcmVkaWN0aW9ucwogIGNvdW50KHBhaXJfaWQsIGNvcnJlY3QpICU+JQogICMgUHJldmFsZW5jZSB0ZXN0CiAgZmlsdGVyKGNvcnJlY3QpICU+JQogIHNwbGl0KC4kcGFpcl9pZCkgJT4lCiAgbWFwX2RmcigKICAgIC5mID0gfi54ICU+JQogICAgICBzZWxlY3QobikgJT4lCiAgICAgIGRlZnJhbWUoKSAlPiUKICAgICAgYmlub20udGVzdCh4ID0gLiwgbiA9IDIxLCBwID0gMC41LCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikgJT4lCiAgICAgIHRpZHkoKSwKICAgIC5pZCA9ICJwYWlyX2lkIgogICkgJT4lCiAga2FibGUoY2FwdGlvbiA9ICJQcmV2YWxlbmNlIHRlc3QgKD4gNTAlKSIpCmBgYAoKV2UnZCBwcmV2aW91c2x5IG5vdGVkIHRoYXQgYmV0d2Vlbm5lc3Mgc2VlbXMgdG8gdHJhY2sgZGlzY3JlcGFuY2llcyBiZXR3ZWVuIGEgbWFuYWdlcidzIHRydWUgdmVyc3VzIHBlcmNlaXZlZCBjZW50cmFsaXR5LiBEb2VzIFNSIGNlbnRyYWxpdHkgdHJhY2sgd2l0aCBiZXR3ZWVubmVzcz8gVGhlIGxvZXNzIGN1cnZlIHN1Z2dlc3RzIHRoZSByZWxhdGlvbnNoaXAgaXMgbm9ubGluZWFyLCBidXQgdGhlcmUgaXMgYSBzdHJvbmdseSBzaWduaWZpY2FudCByYW5rIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHR3by4KCmBgYHtyIHRlc3Qtc3ItYmV0d2Vlbm5lc3N9CnNyX2NlbnRyYWxpdHkgJT4lCiAgZ3JvdXBfYnkobmFtZSA9IG5vZGVfaWQpICU+JQogIHN1bW1hcmlzZShzcl9jZW50cmFsaXR5ID0gbWVhbihzcl9jZW50cmFsaXR5KSkgJT4lCiAgbGVmdF9qb2luKGNlbnRyYWxpdHlfZGlmZmVyZW5jZXMpICU+JQogIGdncGxvdChhZXMoeD1zcl9jZW50cmFsaXR5LCB5PUJldHdlZW5uZXNzKSkgKwogIGdnICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCiAgZ2VvbV9sYWJlbChhZXMobGFiZWwgPSBuYW1lKSkgKwogIHhsYWIoIlN1Y2Nlc3NvciBSZXByZXNlbnRhdGlvbiBcdTAzQjMgPSAwLjciKQoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IiwgImNlbnRyYWxpdHlfc3JfdnNfYmV0d2Vlbm5lc3MucGRmIiksCiAgICB3aWR0aCA9IDYsIGhlaWdodCA9IDQsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9Cgpzcl9jZW50cmFsaXR5ICU+JQogIGdyb3VwX2J5KG5hbWUgPSBub2RlX2lkKSAlPiUKICBzdW1tYXJpc2Uoc3JfY2VudHJhbGl0eSA9IG1lYW4oc3JfY2VudHJhbGl0eSkpICU+JQogIGxlZnRfam9pbihjZW50cmFsaXR5X2RpZmZlcmVuY2VzKSAlPiUKICB3aXRoKGNvci50ZXN0KEJldHdlZW5uZXNzLCBzcl9jZW50cmFsaXR5LCBtZXRob2QgPSAic3BlYXJtYW4iLCBleGFjdCA9IEZBTFNFKSkgJT4lCiAgdGlkeSgpICU+JQogIGthYmxlKGNhcHRpb24gPSAiQmV0d2Vlbm5lc3MgdnMgU1IgZ2FtbWEgMC43IikKYGBgCgoKIyBDb21wYW55IGxlYWRlcnNoaXAKClNvIGZhciwgd2UgaGF2ZSBub3QgcHJvdmlkZWQgdGhlIG1vZGVsIHdpdGggYW55IHByaXZpbGVnZWQga25vd2xlZGdlIGFib3V0IHRoZSBjb21wYW55J3Mgc2VuaW9yIGxlYWRlcnNoaXAgaGllcmFyY2h5LiBZZXQsIHVzaW5nIG9ic2VydmF0aW9ucyBjb25zdHJhaW5lZCBieSB0aGUgbmV0d29yayBzdHJ1Y3R1cmUsIHRoZSBtb2RlbCBoYXMgaWRlbnRpZmllZCBtb3N0IG9mIHRoZSBjb21wYW55J3MgbGVhZGVyc2hpcCBhbnl3YXlzLgoKVGhlIENFTyBpcyBjb2RlZCBhcyBub2RlIDcsIGFuZCB0aGUgZm91ciBWaWNlIFByZXNpZGVudHMgYXJlIGNvZGVkIGFzIDIsIDE0LCAxOCwgYW5kIDIxLiBXZSBzZWUgY2xlYXIgZXZpZGVuY2UgdGhhdCB0aGUgbW9kZWwgaWRlbnRpZmllcyBub2RlcyAyLCA3LCAxOCwgYW5kIDIxIGFzIGJlaW5nIGNlbnRyYWwgZmlndXJlcywgYnV0IHRoZSBtb2RlbCBtYWtlcyBjb25zcGljdW91c2x5IGluY29ycmVjdCBwcmVkaWN0aW9ucyBhYm91dCBtYW5hZ2VyIDE0LgoKQ291bGQgdGhlIG1vZGVsIGluIHByaW5jaXBsZSBkbyBhIGJldHRlciBqb2IgYXQgaWRlbnRpZnlpbmcgbWFuYWdlciAxNCBhcyBhIGNlbnRyYWwgbmV0d29yayBtZW1iZXI/IFRvIHRlc3QgdGhpcywgd2UnbGwgbWFrZSBvbmUgYWRkaXRpb25hbCBhc3N1bXB0aW9uIGFib3V0IG1hbmFnZXJzJyBvYnNlcnZhdGlvbnM6IHRoZXkgb2JzZXJ2ZSB0aGUgc2VuaW9yIGxlYWRlcnNoaXAgdHdpY2UgYXMgbXVjaCBhcyBvdGhlciBuZXR3b3JrIG1lbWJlcnMuCgpgYGB7ciBsZWFkZXJzaGlwLWNvbXB1dGUtc3J9CnNyX29ic2VydmF0aW9uc19sZWFkZXJzaGlwIDwtIG9ic19lZGdlbGlzdF9vdXQgJT4lCiAgIyBEb3VibGUtY291bnQgQ0VPIGFuZCBWUHMKICBiaW5kX3Jvd3MoCiAgICBvYnNfZWRnZWxpc3Rfb3V0ICU+JQogICAgICBmaWx0ZXIoZnJvbSAlaW4lIGMoMiwgNywgMTQsIDE4LCAyMSkgfCB0byAlaW4lIGMoMiwgNywgMTQsIDE4LCAyMSkpCiAgKSAlPiUKICBleHBhbmRfZ3JpZChyZXAgPSAxOjEwMCkgJT4lCiAgZ3JvdXBfYnkoc3ViX2lkLCByZXApICU+JQogIHNsaWNlX3NhbXBsZShwcm9wID0gMSkgJT4lCiAgdW5ncm91cCgpCgpzcl9sZWFkZXJzaGlwIDwtIHNyX29ic2VydmF0aW9uc19sZWFkZXJzaGlwICU+JQogIGV4cGFuZF9ncmlkKGdhbW1hID0gc2VxKDAuMSwgMC45LCAwLjEpLCAuKSAlPiUKICBncm91cF9ieShzdWJfaWQsIGdhbW1hKSAlPiUKICBuZXN0KCkgJT4lCiAgbXV0YXRlKAogICAgc3IgPSBtYXAyKAogICAgICAueCA9IGRhdGEsIC55ID0gZ2FtbWEsCiAgICAgIH5idWlsZF9yZXBfc3IoLngsIHRoaXNfYWxwaGEgPSAwLjEsIHRoaXNfZ2FtbWEgPSAueSkKICAgICkKICApICU+JQogIHVubmVzdChzcikgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtZGF0YSkgJT4lCiAgbXV0YXRlKGdhbW1hID0gZ2FtbWEgKiAxMCkgJT4lCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gZ2FtbWEsCiAgICBuYW1lc19wcmVmaXggPSAic3IiLAogICAgdmFsdWVzX2Zyb20gPSBzcl92YWx1ZQogICkKYGBgCgpXZSdsbCB0ZXN0IHdoZXRoZXIgdGhlIG1vZGVsIGdvb2RuZXNzLW9mLWZpdCBpcyBiZXR0ZXIgYXQgJFxnYW1tYSA9IDAuNyQsIHdoaWNoIHdhcyB0aGUgYmVzdC1maXR0aW5nIG1vZGVsIGZyb20gYmVmb3JlOgoKYGBge3IgbGVhZGVyc2hpcC1iaWN9CnRlc3Rfc3I3X2xlYWRlcnNoaXAgPC0ga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICByZW5hbWUoY2hvaWNlID0gZWRnZSkgJT4lCiAgbGVmdF9qb2luKHNjaGVtYV9leHBlcnRzX291dCwgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpKSAlPiUKICBsZWZ0X2pvaW4oc3JfbGVhZGVyc2hpcCwgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpKSAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNyArICgxICsgc3I3IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKYmluZF9yb3dzKAogIGdsYW5jZSh0ZXN0X3NyN19vdXQpICU+JSBtdXRhdGUobW9kZWwgPSAic3I3IHN0YW5kYXJkIiksCiAgZ2xhbmNlKHRlc3Rfc3I3X2xlYWRlcnNoaXApICU+JSBtdXRhdGUobW9kZWwgPSAic3I3IGxlYWRlcnNoaXAgMngiKQopICU+JQogIGthYmxlKCkKYGBgCgpgYGB7ciBsZWFkZXJzaGlwLWNlbnRyYWxpdHl9CnNyX2NlbnRyYWxpdHlfbGVhZGVyc2hpcCA8LSBzcl9sZWFkZXJzaGlwICU+JQogICMgU1IgY2VudHJhbGl0eSBmcm9tIGJlc3QgdmFyaWFudAogIGZpbHRlcihmcm9tICE9IHRvKSAlPiUKICBncm91cF9ieShzdWJfaWQsIG5vZGVfaWQgPSB0bykgJT4lCiAgc3VtbWFyaXNlKHNyX2NlbnRyYWxpdHkgPSBtZWFuKHNyNyksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogICMgUGVyY2VpdmVkIGNlbnRyYWxpdHkKICBsZWZ0X2pvaW4oCiAgICBrcmFja2hhcmR0X2FsbG9jZW50cmljICU+JQogICAgICBncm91cF9ieShzdWJfaWQsIG5vZGVfaWQgPSB0bykgJT4lCiAgICAgIHN1bW1hcmlzZShwZXJjZWl2ZWRfY2VudHJhbGl0eSA9IG1lYW4oZWRnZSksIC5ncm91cHMgPSAiZHJvcCIpLAogICAgYnkgPSBjKCJzdWJfaWQiLCAibm9kZV9pZCIpCiAgKQoKc3JfY2VudHJhbGl0eV9jb3JyX2xlYWRlcnNoaXAgPC0gc3JfY2VudHJhbGl0eV9sZWFkZXJzaGlwICU+JQogIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgbmVzdCgpICU+JQogIG11dGF0ZSgKICAgIHNwZWFybWFuID0gbWFwX2RibCgKICAgICAgLnggPSBkYXRhLAogICAgICAuZiA9IH53aXRoKAogICAgICAgIC54LCBjb3IoCiAgICAgICAgICBzcl9jZW50cmFsaXR5LCBwZXJjZWl2ZWRfY2VudHJhbGl0eSwgbWV0aG9kID0gInNwZWFybWFuIgogICAgICAgICkKICAgICAgKQogICAgKQogICkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtZGF0YSkKCnNyX2NlbnRyYWxpdHlfY29ycl9sZWFkZXJzaGlwICU+JQogIG11dGF0ZShzcGVhcm1hbiA9IHRhbmgoc3BlYXJtYW4pKSAlPiUKICBzZWxlY3Qoc3BlYXJtYW4pICU+JQogIGRlZnJhbWUoKSAlPiUKICB0LnRlc3QoKSAlPiUKICB0aWR5KCkgJT4lCiAga2FibGUoCiAgICBjYXB0aW9uID0gc3RyX2MoCiAgICAgICJ0LXRlc3Qgb2YgdGhlIGF2ZXJhZ2UgU3BlYXJtYW4gY29ycmVsYXRpb24gYmV0d2VlbiBwZXJjZWl2ZWQgYW5kICIsCiAgICAgICJTUi1wcmVkaWN0ZWQgY2VudHJhbGl0eSAoei10cmFuc2Zvcm1lZCkiCiAgICApCiAgKQoKc3JfY2VudHJhbGl0eV9jb3JyX2xlYWRlcnNoaXAgJT4lCiAgc3VtbWFyaXNlKG1lYW5fc3BlYXJtYW4gPSBtZWFuKHNwZWFybWFuKSkgJT4lCiAga2FibGUoKQpgYGAKCmBgYHtyIGxlYWRlcnNoaXAtcGxvdC1jZW50cmFsaXR5fQpwbG90X3NyX2NlbnRyYWxpdHlfZ3JvdXBfbGVhZGVyc2hpcCA8LSBzcl9jZW50cmFsaXR5X2xlYWRlcnNoaXAgJT4lCiAgIyBHZXQgZWFjaCBzdWJqZWN0J3MgcmFuay1vcmRlcmVkIHBlcmNlaXZlZCBhbmQgU1ItcHJlZGljdGVkIGNlbnRyYWxpdHkKICBncm91cF9ieShzdWJfaWQpICU+JQogIG11dGF0ZShhY3Jvc3MoZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLCB+cmFuaygueCwgdGllcy5tZXRob2QgPSAibWluIikpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBBdmVyYWdlIGFjcm9zcyBzdWJqZWN0cyB0byBnZXQgZ3JvdXAtbGV2ZWwgcmVzdWx0cwogIGdyb3VwX2J5KG5vZGVfaWQpICU+JQogIHN1bW1hcmlzZShhY3Jvc3MoZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLCBtZWFuKSkgJT4lCiAgIyBGb3IgY29sb3ItY29kaW5nIHR3byBwYWlycyBvZiBtYW5hZ2VycyB3aXRoIGVxdWl2YWxlbnQgZGVncmVlIGNlbnRyYWxpdHksCiAgIyBidXQgZGlmZmVyZW50IHBlcmNlaXZlZCBjZW50cmFsaXR5CiAgbXV0YXRlKAogICAgY29sb3Jjb2RlID0gY2FzZV93aGVuKAogICAgICBub2RlX2lkICVpbiUgYygxLCA3KSB+ICJhIiwKICAgICAgbm9kZV9pZCAlaW4lIGMoMTgsIDIxKSB+ICJiIgogICAgKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4PXBlcmNlaXZlZF9jZW50cmFsaXR5LCB5PXNyX2NlbnRyYWxpdHkpKSArCiAgZ2cgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gbm9kZV9pZCwgZmlsbCA9IGNvbG9yY29kZSksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYTZjZWUzIiwgIiNiMmRmOGEiKSwgbmEudmFsdWUgPSAiZ3JleTk1IikgKwogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIlBlcmNlaXZlZCBjZW50cmFsaXR5IChyYW5rLW9yZGVyZWQpIikgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlNSIGNlbnRyYWxpdHkgKHJhbmstb3JkZXJlZCkiKSArCiAgZ2d0aXRsZSgiUGVyY2VpdmVkIHZzIFN1Y2Nlc3NvciBDZW50cmFsaXR5IChHcm91cC1MZXZlbCkiKQoKcGxvdF9zcl9jZW50cmFsaXR5X2dyb3VwX2xlYWRlcnNoaXAKCnBsb3Rfc3JfY2VudHJhbGl0eV9pbmRpdmlkdWFsX2xlYWRlcnNoaXAgPC0gc3JfY2VudHJhbGl0eV9sZWFkZXJzaGlwICU+JQogICMgR2V0IGVhY2ggc3ViamVjdCdzIHJhbmstb3JkZXJlZCBwZXJjZWl2ZWQgYW5kIFNSLXByZWRpY3RlZCBjZW50cmFsaXR5CiAgZ3JvdXBfYnkoc3ViX2lkKSAlPiUKICBtdXRhdGUoYWNyb3NzKGVuZHNfd2l0aCgiX2NlbnRyYWxpdHkiKSwgfnJhbmsoLngsIHRpZXMubWV0aG9kID0gIm1pbiIpKSkgJT4lCiAgdW5ncm91cCgpICU+JQogICMgRm9ybWF0dGluZyBmb3IgcGxvdHRpbmcKICBwaXZvdF9sb25nZXIoCiAgICBlbmRzX3dpdGgoIl9jZW50cmFsaXR5IiksCiAgICBuYW1lc190byA9ICJtZXRyaWMiLAogICAgdmFsdWVzX3RvID0gImNlbnRyYWxpdHkiCiAgKSAlPiUKICBtdXRhdGUoCiAgICBub2RlX2lkID0gZmFjdG9yKG5vZGVfaWQpLAogICAgc3ViX2lkID0gc3RyX3BhZChzdWJfaWQsIHdpZHRoID0gMiwgc2lkZSA9ICJsZWZ0IiwgcGFkID0gIjAiKSwKICAgIHN1Yl9pZCA9IHN0cl9jKCJNYW5hZ2VyICIsIHN1Yl9pZCkKICApICU+JQogIGdncGxvdChhZXMoeD1ub2RlX2lkLCB5PWNlbnRyYWxpdHksIGZpbGw9bWV0cmljKSkgKwogIGZhY2V0X3dyYXAofnN1Yl9pZCwgbnJvdyA9IDMpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjUpICsKICBjb29yZF9wb2xhcigpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgKICAgIG5hbWUgPSAiQ2VudHJhbGl0eSIsCiAgICBsYWJlbHMgPSBjKCJQZXJjZWl2ZWQgKEVtcGlyaWNhbCkiLCAiU3VjY2Vzc29yIFJlcHJlc2VudGF0aW9uIChTaW11bGF0ZWQpIikKICApICsKICBnZ3RpdGxlKCJQZXJjZWl2ZWQgdnMgU3VjY2Vzc29yIENlbnRyYWxpdHkgKEluZGl2aWR1YWwtTGV2ZWwpIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEzKSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMSksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC43NSwgImxpbmVzIiksCiAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKGMoMCwgMCwgMCwgMCksIHVuaXQgPSAibGluZXMiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCgpwbG90X3NyX2NlbnRyYWxpdHlfaW5kaXZpZHVhbF9sZWFkZXJzaGlwCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic3JfY2VudHJhbGl0eV9ncm91cF9sZWFkZXJzaGlwLnBkZiIpLAogICAgcGxvdCA9IHBsb3Rfc3JfY2VudHJhbGl0eV9ncm91cF9sZWFkZXJzaGlwLAogICAgd2lkdGggPSA2LCBoZWlnaHQgPSA0LAogICAgZGV2aWNlID0gY2Fpcm9fcGRmLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKICAKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic3JfY2VudHJhbGl0eV9pbmRpdmlkdWFsX2xlYWRlcnNoaXAucGRmIiksCiAgICBwbG90ID0gcGxvdF9zcl9jZW50cmFsaXR5X2luZGl2aWR1YWxfbGVhZGVyc2hpcCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKIyBGaWd1cmVzIGZvciBwYXBlcgoKYGBge3IgcGFwZXItbmV0d29yay1ncmFwaH0KbmV0d29ya19mb3JfcGFwZXIgPC0ga3JhY2toYXJkdF9nICU+JQogIG11dGF0ZSgKICAgIERlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKG1vZGUgPSAiaW4iKSwKICAgIG5vZGVfY29sb3Jjb2RlID0gY2FzZV93aGVuKAogICAgICBuYW1lICVpbiUgYygxLCA3KSB+ICJhIiwKICAgICAgbmFtZSAlaW4lIGMoMTgsIDIxKSB+ICJiIgogICAgKQogICkgJT4lCiAgIyBUbyBjbGVhbiB1cCBzb21lIG9mIHRoZSBvdmVycGxvdHRpbmcKICBhY3RpdmF0ZSgiZWRnZXMiKSAlPiUKICBtdXRhdGUoCiAgICBlZGdlX2NvbG9yY29kZSA9IGNhc2Vfd2hlbigKICAgICAgZnJvbSAlaW4lIGMoMSwgNykgfCB0byAlaW4lIGMoMSwgNykgfiAiYSIsCiAgICAgIGZyb20gJWluJSBjKDE4LCAyMSkgfCB0byAlaW4lIGMoMTgsIDIxKSB+ICJiIgogICAgKQogICkgJT4lCiAgIyBQbG90IHRoZSAiZ3JvdW5kIHRydXRoIiBuZXR3b3JrCiAgZ2dyYXBoKGxheW91dCA9ICJzdHJlc3MiKSArCiAgZ2VvbV9lZGdlX2xpbmsoCiAgICBhZXMoCiAgICAgIHN0YXJ0X2NhcCA9IGxhYmVsX3JlY3Qobm9kZTEubmFtZSwgcGFkZGluZyA9IG1hcmdpbigxNSwgMTUsIDE1LCAxNSkpLAogICAgICBlbmRfY2FwID0gbGFiZWxfcmVjdChub2RlMi5uYW1lLCBwYWRkaW5nID0gbWFyZ2luKDE1LCAxNSwgMTUsIDE1KSksCiAgICAgIGNvbG9yID0gZWRnZV9jb2xvcmNvZGUKICAgICksCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoNSwgInB0IiksIHR5cGUgPSAiY2xvc2VkIiksCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9ub2RlX2xhYmVsKAogICAgYWVzKGxhYmVsID0gbmFtZSwgc2l6ZSA9IERlZ3JlZSwgZmlsbCA9IG5vZGVfY29sb3Jjb2RlKSwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygzLCAxMCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYTZjZWUzIiwgIiNiMmRmOGEiKSwgbmEudmFsdWUgPSAiZ3JleTk1IikgKwogIHNjYWxlX2VkZ2VfY29sb3JfbWFudWFsKAogICAgdmFsdWVzID0gYygiIzFmNzhiNCIsICIjMzNhMDJjIiksIG5hLnZhbHVlID0gImdyZXk4MCIKICApICsKICBnZ3RpdGxlKCJBZHZpY2UgTmV0d29yayAoS3JhY2toYXJkdCAxOTg3KSIpICsKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTMpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEzKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKbmV0d29ya19mb3JfcGFwZXIKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJuZXR3b3JrX2dyYXBoLnBkZiIpLAogICAgcGxvdCA9IG5ldHdvcmtfZm9yX3BhcGVyLAogICAgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNSwKICAgIGRldmljZSA9IGNhaXJvX3BkZiwgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgpgYGB7ciBwYXBlci1yZXByZXNlbnRhdGlvbn0KcmVwcmVzZW50YXRpb25fZm9yX3BhcGVyIDwtICgKICAocGxvdF9jaG9pY2UgKyBnZ3RpdGxlKCJQZXJjZWl2ZWQgKEVtcGlyaWNhbCkiKSkgfAogICAgcGxvdF9zcjdfb3V0ICsgZ2d0aXRsZSgiU3VjY2Vzc29yIFJlcC4gXHUwM0IzID0gMC43IChTaW11bGF0ZWQpIikKKSArCiAgcGxvdF9hbm5vdGF0aW9uKAogICAgdGl0bGUgPSAiTmV0d29yayBSZXByZXNlbnRhdGlvbiIsCiAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBoanVzdCA9IDAuNSkpCiAgKQoKcmVwcmVzZW50YXRpb25fZm9yX3BhcGVyCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAicmVwcmVzZW50YXRpb24ucGRmIiksCiAgICBwbG90ID0gcmVwcmVzZW50YXRpb25fZm9yX3BhcGVyLAogICAgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNSwKICAgIGRldmljZSA9IGNhaXJvX3BkZiwgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgpgYGB7ciBwYXBlci1jZW50cmFsaXR5fQpjZW50cmFsaXR5X2luZGl2aWR1YWxfZm9yX3BhcGVyIDwtIHNyX2NlbnRyYWxpdHkgJT4lCiAgZmlsdGVyKHN1Yl9pZCAlaW4lIGMoMTcsIDE5KSkgJT4lCiAgIyBHZXQgZWFjaCBzdWJqZWN0J3MgcmFuay1vcmRlcmVkIHBlcmNlaXZlZCBhbmQgU1ItcHJlZGljdGVkIGNlbnRyYWxpdHkKICBncm91cF9ieShzdWJfaWQpICU+JQogIG11dGF0ZShhY3Jvc3MoZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLCB+cmFuaygueCwgdGllcy5tZXRob2QgPSAibWluIikpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBGb3JtYXR0aW5nIGZvciBwbG90dGluZwogIHBpdm90X2xvbmdlcigKICAgIGVuZHNfd2l0aCgiX2NlbnRyYWxpdHkiKSwKICAgIG5hbWVzX3RvID0gIm1ldHJpYyIsCiAgICB2YWx1ZXNfdG8gPSAiY2VudHJhbGl0eSIKICApICU+JQogIG11dGF0ZSgKICAgIG5vZGVfaWQgPSBmYWN0b3Iobm9kZV9pZCksCiAgICBzdWJfaWQgPSBzdHJfcGFkKHN1Yl9pZCwgd2lkdGggPSAyLCBzaWRlID0gImxlZnQiLCBwYWQgPSAiMCIpLAogICAgc3ViX2lkID0gc3RyX2MoIk1hbmFnZXIgIiwgc3ViX2lkKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4PW5vZGVfaWQsIHk9Y2VudHJhbGl0eSwgZmlsbD1tZXRyaWMpKSArCiAgZmFjZXRfd3JhcCh+c3ViX2lkKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC41KSArCiAgY29vcmRfcG9sYXIoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoCiAgICBuYW1lID0gIkNlbnRyYWxpdHkiLAogICAgbGFiZWxzID0gYygiUGVyY2VpdmVkIChFbXBpcmljYWwpIiwgIlN1Y2Nlc3NvciBSZXAuIChTaW11bGF0ZWQpIikKICApICsKICBnZ3RpdGxlKCJJbmRpdmlkdWFsLUxldmVsIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEzKSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMSksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC43NSwgImxpbmVzIiksCiAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKGMoMCwgMCwgMCwgMCksIHVuaXQgPSAibGluZXMiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCgpjZW50cmFsaXR5X2Zvcl9wYXBlciA8LSAoCiAgKAogICAgcGxvdF9zcl9jZW50cmFsaXR5X2dyb3VwICsKICAgICAgZ2d0aXRsZSgiR3JvdXAtTGV2ZWwiKSArCiAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlN1Y2Nlc3NvciBSZXAuIGNlbnRyYWxpdHkgKHJhbmstb3JkZXJlZCkiKQogICkgfAogICAgY2VudHJhbGl0eV9pbmRpdmlkdWFsX2Zvcl9wYXBlcgopICsKICBwbG90X2Fubm90YXRpb24oCiAgICB0aXRsZSA9ICJQZXJjZWl2ZWQgdnMgU3VjY2Vzc29yIENlbnRyYWxpdHkiLAogICAgdGhlbWUgPSB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMywgaGp1c3QgPSAwLjUpKQogICkKCmNlbnRyYWxpdHlfZm9yX3BhcGVyCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAiY2VudHJhbGl0eS5wZGYiKSwKICAgIHBsb3QgPSBjZW50cmFsaXR5X2Zvcl9wYXBlciwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDUsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKCiMgU2F2ZSBkYXRhCgpJdCB3YXMgYSBiaXQgb2YgYSBwYWluIGdldHRpbmcgdGhlIHJhdyBkYXRhIGludG8gc2hhcGUsIHNvIHdlJ2xsIHNhdmUgdGhlIGNsZWFuZWQgdmVyc2lvbnMgZm9yIHBvc3Rlcml0eS4KCmBgYHtyIHNhdmUtZGF0YX0KaWYgKGtuaXR0aW5nKSB7CiAga3JhY2toYXJkdF9lZ29jZW50cmljICU+JQogICAgd3JpdGVfY3N2KGhlcmUoImRhdGEiLCAia3JhY2toYXJkdCIsICJjbGVhbl9lZ29jZW50cmljLmNzdiIpKQogIAogIGtyYWNraGFyZHRfYWxsb2NlbnRyaWMgJT4lCiAgICByZW5hbWUoY2hvaWNlID0gZWRnZSkgJT4lCiAgICB3cml0ZV9jc3YoaGVyZSgiZGF0YSIsICJrcmFja2hhcmR0IiwgImNsZWFuX2FsbG9jZW50cmljLmNzdiIpKQp9CmBgYAoKCiMgU2Vzc2lvbiBpbmZvCgpgYGB7ciBzZXNzaW9uLWluZm99CnNlc3Npb25JbmZvKCkKYGBgCgo=